In c++ can we cast an object to an integer ?
Clarifying my question - Suppose I have created an interface to handle file management task like create file, open file, read, write and I want to have one unique handle for every instance of a file. To achieve this can I create a file handle for each instance of the file interface by just type casting that instance to integer ?
To all - I hope now i am clear.
Not all objects. Every object in C++ has a type. That type of an object defines whether a cast to int exists, and if so, what algorithm is used.
If you have an object and want to cast it to int then you need to explicitly provide operator int for that class.
class File
{
public:
...
...
operator int() { return int(this); }
...
}
Then
File myFile;
int myFileHandle = myFile;
I would rather convert to a long type. This is safer when a pointer value is converted to an integral type on an x64 machine. You can just use reinterpret_cast<long>(myInterfacePointer) in that case.
you can, but it depend on the sizeof(YourObject) compared to sizeof(int), by casting any object to int you will access the first 4 bytes part of your object (assuming sizeof(int) == 4), if your object is smaller than sizeof(int) somewhere you will get access violation or crash. to cast :
`
MyObject object;
int castedObject = *((int*)&object);
`
to cast without pointer intermediate, you must provide typecast operator inside MyObject class. or you can declare global static function of int& operator=(const MyObject& object){...}
Edit: Since you are mapping files to a unique handle, you can use a std::vector<std::string> or a vector<shared_ptr<fstream> > or a vector<FILE*>.
On a POSIX-compliant system there is also fileno to convert a FILE* into its file descriptor which is an int.
To get the hash: Use the hash_value function from boost.
To convert any value to integer lexically: Use the lexical_cast<int> function from boost
To cast the value to integer: Just use (int)value.
For the above to work, the class you're going to convert needs to implement some special member functions e.g. operator<< and operator int.
To convert an object into an arbitrary unique integer, use (int)&value.
To get a random integer, use rand().
Why not just get the file descriptor/handle/whatever ID from the operating system and use that? Most systems have some kind of concept like that.
Consider using void * instead of int for the handles if you really want them to be pointers. Then casting a pointer-to-object to a handle is easy, and you can still hide the implementation away.
In response to #potatoswatter's comment to my first response.
I don't like the idea of casting objects. I would rather use a hashing function that produces an integer hash, say based on the filename or read/write flags. Now, I have to post another answer
class File
{
public:
...
...
operator int();
...
private:
char fileName[];
int flags;
};
The integer conversion operator is now a hashing function:
File::operator int()
{
int hash = 0;
int c;
char *str = fileName;
while (c = *str++)
hash += c;
hash += flags;
return hash;
}
I know the hash function is lousy. But you can avoid casts that are lousier and come up with your own hashing function that suits your needs better.
Related
I am writing a parser in C++ to parse a well defined binary file. I have declared all the required structs. And since only particular fields are of interest to me, so in my structs I have skipped non-required fields by creating char array of size equal to skipped bytes. So I am just reading the file in char array and casting the char pointer to my struct pointer. Now problem is that all data fields in that binary are in big endian order, so after typecasting I need to change the endianness of all the struct fields. One way is to do it manually for each and every field. But there are various structs with many fields, so it'll be very cumbersome to do it manually. So what's the best way to achieve this. And since I'll be parsing very huge such files (say in TB's), so I require a fast way to do this.
EDIT : I have use attribute(packed) so no need to worry about padding.
If you can do misaligned accesses with no penalty, and you don't mind compiler- or platform-specific tricks to control padding, this can work. (I assume you are OK with this since you mention __attribute__((packed))).
In this case the nicest approach is to write value wrappers for your raw data types, and use those instead of the raw type when declaring your struct in the first place. Remember the value wrapper must be trivial/POD-like for this to work. If you have a POSIX platform you can use ntohs/ntohl for the endian conversion, it's likely to be better optimized that whatever you write yourself.
If misaligned accesses are illegal or slow on your platform, you need to deserialize instead. Since we don't have reflection yet, you can do this with the same value wrappers (plus an Ignore<N> placeholder that skips N bytes for fields you're not interested), and declare them in a tuple instead of a struct - you can iterate over the members in a tuple and tell each to deserialize itself from the message.
One way to do that is combine C preprocessor with C++ operators. Write a couple of C++ classes like this one:
#include "immintrin.h"
class FlippedInt32
{
int value;
public:
inline operator int() const
{
return _bswap( value );
}
};
class FlippedInt64
{
__int64 value;
public:
inline operator __int64() const
{
return _bswap64( value );
}
};
Then,
#define int FlippedInt32
before including the header that define these structures. #undef immediately after the #include.
This will replace all int fields in the structures with FlippedInt32, which has the same size but returns flipped bytes.
If it’s your own structures which you can modify you don’t need the preprocessor part. Just replace the integers with the byte-flipping classes.
If you can come up with a list of offsets (in-bytes, relative to the top of the file) of the fields that need endian-conversion, as well as the size of those fields, then you could do all of the endian-conversion with a single for-loop, directly on the char array. E.g. something like this (pseudocode):
struct EndianRecord {
size_t offsetFromTop;
size_t fieldSizeInByes;
};
std::vector<EndianRecord> todoList;
// [populate the todo list here...]
char * rawData = [pointer to the raw data]
for (size_t i=0; i<todoList.size(); i++)
{
const EndianRecord & er = todoList[i];
ByteSwap(&rawData[er.offsetFromTop], er.fieldSizeBytes);
}
struct MyPackedStruct * data = (struct MyPackedStruct *) rawData;
// Now you can just read the member variables
// as usual because you know they are already
// in the correct endian-format.
... of course the difficult part is coming up with the correct todoList, but since the file format is well-defined, it should be possible to generate it algorithmically (or better yet, create it as a generator with e.g. a GetNextEndianRecord() method that you can call, so that you don't have to store a very large vector in memory)
I'm developing a parser of Adobe Type 1 font, using C++ language. And there is a problem when I tried to decode the DICT Data.
The operands in the DICT, which are stored as byte-sequence in the PDF file, may be either integer or real number.
I defined a function, whose prototype is getOperandVal(unsigned char* buf), to decode the sequence to number. And the problem appeared.
Before parse the buf, we can not know the buf is real or integer number. So I can not determine the return-value type, which should be int or double.
A solution is to use a struct as the return-value type. The struct is like below:
typedef struct
{
int interger;
double real;
bool bReal;
}RET;
Then the function prototype is:
RET getOperandVal(unsigned char* buf);
But I think it is not compact. First of all, it is inconvenient to use. Second, the program will run slower when the size of data is big.
Can anyone give me a better solution? Can template do it?
Thank you very much!
Addition:
The program will transfer the operands value into byte-sequence for rewriting into file after edit. Consider the requirement, please.
You can't use templates because you don't know at compile time what type will be returned.
But you can use a union:
struct Int_real {
union {
int integer;
double real;
};
bool is_real;
};
A very good idea is to improve upon it by making it safe (allow access to only the field of the union that is active).
Pretty soon (hopefully), you will be able to use std::any
Template types are evaluated at the compile time, you could not change function prototype dynamically. You could either upscale return value to the biggest size (for example always return double), return a struct or use some variant implementation, like boost::variant.
I'm quite new to reading and writing to files. But basically, I have an assignment where part of it requires me to determine whether a line from a file is an integer or double.
This is the part of the assignment I need help on:
Open the text file and read it's contents one line at a time. Determine if the line read from the file is a double or an integer. You are to place the integers in a vector called iNumbers and the doubles in a vector called dNumbers. The vector iNumbers should hold pointers to the Integer class and dNumbers should hold pointers to the Double class. When you add a value to one of the vectors you should use new and call the constructor that takes a string. For example:
iNumbers.push_back(new Integer("12.23"));
Sample of the file:
12
20
80.5
99.345
70
From what I understand, I think I write code that will read the lines in the file and if they have a "." then those will be doubles, but I am not sure as how to start with that.
Any help as to how I should get started would be very appreciated and thanks in advance.
Beware, in C++ (and not only C++), 1e4 is also double (with value of 10000).
If this is not allowed in the task (and finding . in the number is sufficent), then I would create std::ifstream for the file, read from it using std::getline into a std::string s, then in the string I would s.find('.') and if it is to be found (the result of find != s.npos, pass it into dNumbers as new Double(s), if such constructor exists for your class.
To be pedantic, in the general case the best way to figure out whether or not a string is an integer is to try to convert it to an integer without any error or leftover characters.
Here is a very simple method to do just that (for any type):
template <typename T>
T string_to( const std::string& s )
{
T value;
std::istringstream ss( s );
ss >> value >> std::ws;
if (!ss.eof()) throw std::invalid_argument("T string_to()");
return value;
}
You can now test for any standard integer vs double:
int n;
double d;
try {
n = string_to <int> ("12.3");
// it's an int
}
catch (...) {
try {
n = string_to <double> ("12.3");
// it's a double
}
catch (...) {
// it is neither integer nor double
}
}
If desired, you can specialize the int types to handle things like "0xF3" by unsetting the basefield: ss.unsetf(std::ios::basefield);.
Hope this helps.
Here is a straightforward way you could accomplish this task:
read from the stream using std::getline to a std::string
use std::stof and std::stoi with this string as the parameter to determine the type - if they throw std::invalid_argument or std::out_of_range, conversion could not be done
push_back to one of the arrays, depending on which type was
Glad to see that we are in the same class...
There is more to the assignment that you left out. We have our double.cpp and our integer.cpp files that include constructors that take a string as a parameter if you did your program correctly, that is. So the iNumbers.push_back(new Integer("12.23")); is basically saying "iNumbers" - the name of the vector, ".push_back" - the function that puts the string value onto the stack, "new Integer" - allocating memory for the type Integer, and "12.23" - the actually double value that was used as an example in the form of a string taken from the .txt file.
What you need to do is look through his lecture slides that include the content about I/O files and you should be fine. We even did an example in class.
As far as your basic question about integer and double types, its very simple and I have no idea how you got through the past assignments without knowing the difference, an integer does not have a decimal point and a double does. Now there may be a more complicated definition for an integer and a double type but for Stevenson's class this is the only thing you should think about. Forget what you learned in your math class about integers. The definition is not the same for this class.
Best of luck...
See you in class
-C
I am using the ldap_modify function to change an attribute value using C++ ...
msgid=ldap_modify_ext_s( ld, dnNameval, ldapmod,NULL,NULL );
The problem is the mod_val argument in that function ...
LDAP *id;
dnNameval ="distinguised name";
In the ldapmod there are three values ...
mod_type="attribute to be changed";
mod_op=LDAP_MOD_REPLACE;
ldapmod struct
The ldapmod struct is:
typedef struct ldapmod {
int mod_op;
char *mod_type;
union {
char **modv_strvals;
struct berval **modv_bvals;
} mod_vals;
#define mod_values mod_vals.modv_strvals
#define mod_bvalues mod_vals.modv_bvals
} LDAPMod;
I tried passing the value like this:
mod_vals=(PWCHAR*){"bala",Null};
which resulted in the error
error C2679: binary '=' : no operator found which takes a right-hand operand
of type 'PWCHAR *' (or there is no acceptable conversion)
I also tried this:
mod_vals.modv_strvals=(PWCHAR*) Password1;
mod_vals.modv_bvals=NULL;
but then the array has a null value...
Can anyone help me work out how to pass the values in that variable? Do I need to include any additional header files? I am already using the winldap.h header.
Thanks in advance.
This won't work:
mod_vals = (PWCHAR*){"bala",Null};
You can't assign a value to a union that way. You have to specify which of the members of the union you want to write to. Also, (PWCHAR *) is the wrong type; you're not dealing with wide characters. Even if you were, you can't convert a string just by casting it.
This won't work either:
mod_vals.modv_strvals=(PWCHAR*) Password1;
mod_vals.modv_bvals=NULL;
The modv_strvals member is a pointer-to-pointer, not just a pointer, and it doesn't make sense to write to two members of a union; they're mutually exclusive. Depending on context you either use modv_strvals or modv_bvals, never both.
You probably want to do this:
mod_vals.modv_strvals = {"bala", Null};
I have problem with void * I want to put what contain in a string to output it,I know that in compiling moment the compiler doesn't know what the pointer point to so I think to use a kind of cast(cast the *(void*) to string ) the static_cast:
std::string get_Info_Field (std::string nameTab,int IDF)
{ ostringstream os;
iter=Inst_Data.find(nameTab);
if(iter!= Inst_Data.end())
{ iterF=(iter->second).find(IDF);
if(iterF!=(iter->second).end())
{os<<*static_cast<std::string*>(iterF->second.value);}
else { os<<""; }
}
else { os<<"";}
return os.str();
};
here iterF->second.value is a void* that I want to get its value that can point to any type(int,string,float,long,char..), my question is :is that safe? will return the right value of the pointer whatever the type ? I tested with int it works but I'am not sure for the rest.
please any help will be appreciated.
If you know that the void* happens to point to a std::string then yes, it is safe.
You can't safely cast an pointer to an arbitrary value to a string and expect something sensible to happen; at absolute minimum you also need to know the size of the thing pointed to, and you may also need to watch out for embedded NULs and the like. If you know that it is always a std::string then you can cast to a std::string safely; but you do have to know with certainty, or you're courting a core dump or random output.
No you absolutely cannot do that and expect sensible results if the void* points to say int and you cast it to std::string. You will need to store type information somewhere, either by having a polymorphic class hierarchy to contain your data, by using boost::variant, by writing your own "discriminated union," or some other technique.
Absolutely not safe. How can you be sure that what you're pointing to is a string? How did you reserve this memory in the first place?
Sounds like a design issue - why do you have data blobs floating around whose type you don't know? Are you attempting to implement a variant type?