J
J. Campbell
I have a feeling that I'm doing things all ass-backwards (again ;-),
and would like some advice. What I want to do is:
put some data to memory and then access that memory space as an array
of data-types of my choosing (eg an array of char, short, or int).
The application has to do with generating checksum-type values for
files or strings, so speed is important, as I just want to quickly get
this value then move on to the next task. As such, I don't want to
"properly" bit-shift bytes to ints...rather, I want to put all the
bits in sequential order then access them in chunks sized to the
machine's native integer for bitwise operations.
I had been doing this by using the fstream write() function to dump
the file to a char array (on the heap sized to filesize), then casting
the char array to an int*. This worked fine, but then I learned about
potential alignment problems...that there could be cases that the
location of the char* might be an invalid location for an int*. To
circumvent this potential problem, I made a class, align_int, that
reverses the order...first creating the int array, then casting the
array to a char*, then dumping the file to the char*. This works
because every int* address is accessable as a char*, even though some
char* addresses may NOT be accessable as an int*.
So...now I've got my big, ugly, class that offers pointers of every
native int type to the same memory-space...and it works fine...but I
realize that the class contains pointers that are never used on any
given run. I'm wondering if there's an easier way to do this using a
single void* cast to the proper type as the return value of getter
member functions?
What I need from the class is the ability to request a pointer to the
file as any of the integer data-types. My dumb-ass class follows...
//AlignInt_class.h
#include <string>
class AlignInt{
private:
bool fileOKd(std::string filespec);
void load_file();
std::string type;
public:
AlignInt();
~AlignInt();
void loadfile(std::string filespec);
void loadstring(std::string stringin);
void prealigned(unsigned long* parray, unsigned int byte_len);
unsigned int* ui;
unsigned long* ul;
unsigned short* us;
unsigned char* uc;
int* i;
long* l;
short* s;
char* c;
std::string filespec;
unsigned int len_c; // len of file in bytes (char)
unsigned int len_s; // len of file in shorts
unsigned int len_i; // len of file in int
unsigned int len_l; // len of file in long
bool ok;
void verify();
};
//alignint.cpp
#include "AlignInt_class.h"
#include <iostream>
#include <fstream>
using namespace std;
AlignInt::AlignInt(){
ok = 0;
}
AlignInt::~AlignInt(){
if(ok) delete[] ul;
}
void AlignInt::loadfile(string filename){
if(ok) cout << "ERROR...memory redesignation ERROR 1" << endl;
else{
filespec = filename;
ok = fileOKd(filespec);
if(ok){
load_file();
//ul....defined in load_file
uc = reinterpret_cast<unsigned char*>(ul);
ui = reinterpret_cast<unsigned int*>(ul);
us = reinterpret_cast<unsigned short*>(ul);
i = reinterpret_cast<int*> (ul);
l = reinterpret_cast<long int*> (ul);
s = reinterpret_cast<short int*> (ul);
//c....defined in load_file
// len_c....defined in load_file
// len_l....defined in load_file
len_i = len_l * (sizeof(long int)/sizeof(unsigned int));
len_s = len_l * (sizeof(long int)/sizeof(unsigned short
int));
type = "file";
}else cout << "FILE ERROR: Cannot load: " << filespec << endl;
}
}
void AlignInt::load_file(){
int wordsize = sizeof(unsigned long int);
ifstream in (filespec.c_str(), ios::in | ios::binary);
in.seekg(0, ios::end);
len_c = in.tellg(); // file length in bytes
len_l = (len_c / wordsize) + ((len_c % wordsize) > 0);
//^^^adds one if remainder^^^//
ul = new unsigned long int[len_l];
ul[len_l - 1] = 0; //make sure last byte is cleared before
putting file in array
c = reinterpret_cast<char*>(ul);
in.seekg(0, ios::beg);
in.read(c, len_c);
in.close();
}
void AlignInt::loadstring (string stringin){
if(ok) cout << "ERROR...memory redesignation ERROR 2" << endl;
else{
int wordsize = sizeof(unsigned long int);
len_c = stringin.size();
len_l = (len_c / wordsize) + ((len_c % wordsize) > 0);
ul = new unsigned long int[len_l];
ul[len_l - 1] = 0;
c = reinterpret_cast<char*>(ul);
for(unsigned int j = 0; j < len_c; ++j)
c[j] = stringin[j];
uc = reinterpret_cast<unsigned char*>(ul);
ui = reinterpret_cast<unsigned int*>(ul);
us = reinterpret_cast<unsigned short*>(ul);
i = reinterpret_cast<int*> (ul);
l = reinterpret_cast<long int*> (ul);
s = reinterpret_cast<short int*> (ul);
len_i = len_l * (sizeof(long int)/sizeof(unsigned int));
len_s = len_l * (sizeof(long int)/sizeof(unsigned short int));
ok = true; //string is in memory
type = "string";
}
}
void AlignInt:realigned(unsigned long* parray, unsigned int
byte_len){
if(!ok){ //ok must == 0
int wordsize = sizeof(unsigned long int);
ul = parray;
len_c = byte_len;
len_l = (len_c / wordsize) + ((len_c % wordsize) > 0);
uc = reinterpret_cast<unsigned char*>(ul);
ui = reinterpret_cast<unsigned int*>(ul);
us = reinterpret_cast<unsigned short*>(ul);
i = reinterpret_cast<int*> (ul);
l = reinterpret_cast<long int*> (ul);
s = reinterpret_cast<short int*> (ul);
c = reinterpret_cast<char*>(ul);
len_i = len_l * (sizeof(long int)/sizeof(unsigned int));
len_s = len_l * (sizeof(long int)/sizeof(unsigned short int));
type = "prealigned array";
}else cout << "ERROR...memory redesignation ERROR 3";
}
bool AlignInt::fileOKd(string filespec){
ifstream in(filespec.c_str());
return in.good();
}
void AlignInt::verify(){
cout << "Verifying...\n"
<< "The " << type
<< " Contains " << len_c << " chars\n"
<< "Fits into an array of " << len_s << " short int\n"
<< "Fits into an array of " << len_i << " int\n"
<< "Fits into an array of " << len_l << " long int\n\n"
<< "The following should all point to the same memory
space\n"
<< "p ulong " << ul << "\n"
<< "p long " << l << "\n"
<< "p uint " << ui << "\n"
<< "p int " << i << "\n"
<< "p short " << s << "\n"
<< "p ushort " << s << "\n"
<< "p uchar " << reinterpret_cast<unsigned int*>(uc) <<
"\n"
<< "p char " << reinterpret_cast<int*>(c) << endl;
}
and would like some advice. What I want to do is:
put some data to memory and then access that memory space as an array
of data-types of my choosing (eg an array of char, short, or int).
The application has to do with generating checksum-type values for
files or strings, so speed is important, as I just want to quickly get
this value then move on to the next task. As such, I don't want to
"properly" bit-shift bytes to ints...rather, I want to put all the
bits in sequential order then access them in chunks sized to the
machine's native integer for bitwise operations.
I had been doing this by using the fstream write() function to dump
the file to a char array (on the heap sized to filesize), then casting
the char array to an int*. This worked fine, but then I learned about
potential alignment problems...that there could be cases that the
location of the char* might be an invalid location for an int*. To
circumvent this potential problem, I made a class, align_int, that
reverses the order...first creating the int array, then casting the
array to a char*, then dumping the file to the char*. This works
because every int* address is accessable as a char*, even though some
char* addresses may NOT be accessable as an int*.
So...now I've got my big, ugly, class that offers pointers of every
native int type to the same memory-space...and it works fine...but I
realize that the class contains pointers that are never used on any
given run. I'm wondering if there's an easier way to do this using a
single void* cast to the proper type as the return value of getter
member functions?
What I need from the class is the ability to request a pointer to the
file as any of the integer data-types. My dumb-ass class follows...
//AlignInt_class.h
#include <string>
class AlignInt{
private:
bool fileOKd(std::string filespec);
void load_file();
std::string type;
public:
AlignInt();
~AlignInt();
void loadfile(std::string filespec);
void loadstring(std::string stringin);
void prealigned(unsigned long* parray, unsigned int byte_len);
unsigned int* ui;
unsigned long* ul;
unsigned short* us;
unsigned char* uc;
int* i;
long* l;
short* s;
char* c;
std::string filespec;
unsigned int len_c; // len of file in bytes (char)
unsigned int len_s; // len of file in shorts
unsigned int len_i; // len of file in int
unsigned int len_l; // len of file in long
bool ok;
void verify();
};
//alignint.cpp
#include "AlignInt_class.h"
#include <iostream>
#include <fstream>
using namespace std;
AlignInt::AlignInt(){
ok = 0;
}
AlignInt::~AlignInt(){
if(ok) delete[] ul;
}
void AlignInt::loadfile(string filename){
if(ok) cout << "ERROR...memory redesignation ERROR 1" << endl;
else{
filespec = filename;
ok = fileOKd(filespec);
if(ok){
load_file();
//ul....defined in load_file
uc = reinterpret_cast<unsigned char*>(ul);
ui = reinterpret_cast<unsigned int*>(ul);
us = reinterpret_cast<unsigned short*>(ul);
i = reinterpret_cast<int*> (ul);
l = reinterpret_cast<long int*> (ul);
s = reinterpret_cast<short int*> (ul);
//c....defined in load_file
// len_c....defined in load_file
// len_l....defined in load_file
len_i = len_l * (sizeof(long int)/sizeof(unsigned int));
len_s = len_l * (sizeof(long int)/sizeof(unsigned short
int));
type = "file";
}else cout << "FILE ERROR: Cannot load: " << filespec << endl;
}
}
void AlignInt::load_file(){
int wordsize = sizeof(unsigned long int);
ifstream in (filespec.c_str(), ios::in | ios::binary);
in.seekg(0, ios::end);
len_c = in.tellg(); // file length in bytes
len_l = (len_c / wordsize) + ((len_c % wordsize) > 0);
//^^^adds one if remainder^^^//
ul = new unsigned long int[len_l];
ul[len_l - 1] = 0; //make sure last byte is cleared before
putting file in array
c = reinterpret_cast<char*>(ul);
in.seekg(0, ios::beg);
in.read(c, len_c);
in.close();
}
void AlignInt::loadstring (string stringin){
if(ok) cout << "ERROR...memory redesignation ERROR 2" << endl;
else{
int wordsize = sizeof(unsigned long int);
len_c = stringin.size();
len_l = (len_c / wordsize) + ((len_c % wordsize) > 0);
ul = new unsigned long int[len_l];
ul[len_l - 1] = 0;
c = reinterpret_cast<char*>(ul);
for(unsigned int j = 0; j < len_c; ++j)
c[j] = stringin[j];
uc = reinterpret_cast<unsigned char*>(ul);
ui = reinterpret_cast<unsigned int*>(ul);
us = reinterpret_cast<unsigned short*>(ul);
i = reinterpret_cast<int*> (ul);
l = reinterpret_cast<long int*> (ul);
s = reinterpret_cast<short int*> (ul);
len_i = len_l * (sizeof(long int)/sizeof(unsigned int));
len_s = len_l * (sizeof(long int)/sizeof(unsigned short int));
ok = true; //string is in memory
type = "string";
}
}
void AlignInt:realigned(unsigned long* parray, unsigned int
byte_len){
if(!ok){ //ok must == 0
int wordsize = sizeof(unsigned long int);
ul = parray;
len_c = byte_len;
len_l = (len_c / wordsize) + ((len_c % wordsize) > 0);
uc = reinterpret_cast<unsigned char*>(ul);
ui = reinterpret_cast<unsigned int*>(ul);
us = reinterpret_cast<unsigned short*>(ul);
i = reinterpret_cast<int*> (ul);
l = reinterpret_cast<long int*> (ul);
s = reinterpret_cast<short int*> (ul);
c = reinterpret_cast<char*>(ul);
len_i = len_l * (sizeof(long int)/sizeof(unsigned int));
len_s = len_l * (sizeof(long int)/sizeof(unsigned short int));
type = "prealigned array";
}else cout << "ERROR...memory redesignation ERROR 3";
}
bool AlignInt::fileOKd(string filespec){
ifstream in(filespec.c_str());
return in.good();
}
void AlignInt::verify(){
cout << "Verifying...\n"
<< "The " << type
<< " Contains " << len_c << " chars\n"
<< "Fits into an array of " << len_s << " short int\n"
<< "Fits into an array of " << len_i << " int\n"
<< "Fits into an array of " << len_l << " long int\n\n"
<< "The following should all point to the same memory
space\n"
<< "p ulong " << ul << "\n"
<< "p long " << l << "\n"
<< "p uint " << ui << "\n"
<< "p int " << i << "\n"
<< "p short " << s << "\n"
<< "p ushort " << s << "\n"
<< "p uchar " << reinterpret_cast<unsigned int*>(uc) <<
"\n"
<< "p char " << reinterpret_cast<int*>(c) << endl;
}