Getting the following warning:
ttgload.c(1654): warning C4312: 'type cast': conversion from 'FT_UInt' to 'void *' of greater size
Which seems rather odd.
The line of code in question is this:
if ( FT_List_Find( &loader->composites,
(void*)(unsigned long)glyph_index ) )
and glyph_index is declared FT_UInt.
FT_UInt is typedef unsigned int so it is rather strange to convert an int to a void*.
Any ideas on how to deal with this warning?
FT_UInt is typedef unsigned int so it is rather strange to convert an int to a void*.
Actually it's not. It's perfectly fine and allowed to convert between integers and pointers. A particular application of this is "user parameters" to a function where you register integer or a pointer together with a function callback.
However the two-fold typecast (void*)(unsigned long) is a recipe for getting problems. It's not guaranteed that sizeof(unsigned ling) >= sizeof(void*) which may cause all kinds of problems (i.e. undefined behaviour) of pointers get truncated.
The proper types to use when someone wants an integer that also can hold a pointer are uintptr_t and intptr_t.
Any ideas on how to deal with this warning?
In this particular case it's likely not a cause of problems, because that pointer is going to be cast back to an FT_UInt. In the long run it would make sense to file an issue and change the prototype of FT_List_Find to accept a uintptr_t instead of a pointer; unfortunately this would also break a lot of existing programs.
Related
I am trying to understand some legacy code using AfxBeginThread.
To my understanding LPVOID is defined as a pointer to a void object. I have this function:
Start(LPVOID pParam){
...
int iTemp = (int)pParam;
...
}
And then the call:
int ch1 = 1;
AfxBeginThread(Start(), (LPVOID)ch1);
I am getting the following compiler warning when compiling for 64bit:
warning C4312: 'type cast': conversion from 'int' to 'LPVOID' of greater size
I am
not 100% sure this is a proper use of a pointer
to avoid the warning, I could use a helper function like (LPVOID) PtrToInt(ch1), but that doesn't look right to me as well
Could anyone help me understand the mechanics behind this? I've been trying to find an example online which uses AfxBeginThread in a similar fashion but failed so far.
MS states:
The parameter is a single value. The value the function receives in this parameter is the value that was passed to the constructor when the thread object was created. The controlling function can interpret this value in any manner it chooses. It can be treated as a scalar value or a pointer to a structure containing multiple parameters, or it can be ignored.
This warning occurs because you are compiling on a 64 bit machine where sizeof(void*) is 8 bytes but sizeof(int) is 4.
A proper way to handle this would be to use an integer type for ch1 which is the same size as a void pointer. This is the exact use case for intptr_t.
And so, it should be safe if you use ìntptr_t to hold the ch1 variable. See also this question: C++: Is it safe to cast pointer to int and later back to pointer again?
not 100% sure this is a proper use of a pointer
You have the right hunch. No, it is not proper use of a pointer.
You can pass a pointer to the function.
int ch1 = 1;
int* ptr = &ch1;
AfxBeginThread(Start(), ptr);
I was wondering if it makes sense to cast the result of sizeof?
Example:
Change sizeof(example) to (size_t) sizeof(example)
The return type is std::size_tbut I get the error "Invalid arguements" in many functions (malloc, memset, ...) and after the cast it works. A quick check with printf showed me, that the results stayed the same.
-edited-
As requested a short example function:
__cxa_dependent_exception* __cxxabiv1:: __cxa_allocate_dependent_exception() throw()
{
__cxa_dependent_exception *ps_ret;
ps_ret = static_cast<__cxa_dependent_exception *> (o_exception_pool.allocate (
(size_t) sizeof(__cxa_dependent_exception )));
if (!ps_ret)
{
std::terminate ();
}
memset (ps_ret, 0, (size_t) sizeof(__cxa_dependent_exception ));
return ps_ret;
}
Without the casts this code throws the mentioned error. The full example can be found in the gcc 4.5.4 source code "libstdc++-v3/libsupc++/eh_alloc.cc"
I am using MinGW.
Yes, you can cast result of sizeof, since sizeof(something) is compile time and you will get result in type of (size_t)5 if sizeof(something) returns 5.
Your question condenses to "can you cast std::size_t to another type".
Of course you can, subject to the normal type casting rules. For example, casting this to an int could get you in hot water for a very large type on a system with a 16 bit int. In other words, check that the new type has adequate capacity.
Extra brownie points if you can do that at compile time in C++.
I am currently working on porting from 32 bit to 64 bit. And I am getting a warning:
cast to pointer from integer of different size
In the following code
AcLogFileWrite(
(FILE *) pOut->pTrace->logFileHandle, /* warning in this line */
outRecord,
outRecordLen);
and prototype of AcLogFileWrite() is
int AcLogFileWrite(
FILE * handle,
char * data,
int bytes);
Here the parameter pOut->pTrace->logFileHandle is of type int.
How can I fix this warning?
You can’t store 64 bits in a 32-bit int. If logFileHandle has to store a pointer, the only integer types that can safely do that are uintptr_t or intptr_t from <stdint.h>. Or you can typedef void*. Since you’re porting to a new ABI anyway, binary compatibility is not an issue and this is a good time to fix it.
If you absolutely cannot change the definition of the type from int, then you must compile under the ILP64 model, in which int, long and void* are all 64 bits wide.
If logFileHandle in fact is a file descriptor getting initialised using e.g. open() you want to use fdopen on it and pass the function's result to AcLogFileWrite().
I am a professional software developer but I'm largely unfamiliar with C++ syntax. I am trying to compare the value at the end of a pointer with a double in an inherited C++ project.
The following bit of code successfully grabs the valueAddress from a text file and prints, for example
|"Primary key value"|123.456|
where the 123.456 is the value of the double at the address in the text file.
...
char DebugString[64];
int valueAddress;
fscanf(inputFile, "%s %d", key, &valueAddress);//inputFile declared elsewhere
printf("|");
printf(database->primaryKey);// Defined elsewhere and not the focus of this question
printf("|");
sprintf_s(DebugString,64,"%g",* ((double *)valueAddress));
printf(DebugString);
printf("|");
...
Why then, can't I access the value using:
if ((double *)valueAddress < -0.5)
{...}
as I get the error "error C2440: '>' : cannot convert from 'double' to 'double *'"
I also can't do:
if ((double) *valueAddress < -0.5)
{...}
as I get the error "error C2100: illegal indirection". Creating a variable and trying to assign that doesn't work either.
valueAddress is an integer in a text file, which is the memory address of a double value. So I need to use the int valueAddress as a double pointer. It clearly works when putting the value in the DebugString, so why won't it work in an if statement? How can I get around this?
I'm clearly misunderstanding the syntax here. What have I got wrong?
Using an int to represent the address of a double stored somewhere and attempting to cast an int to a double* is undefined behaviour in C++.
An int might not even be large enough to hold a pointer address. On a 64 bit system, a 32 bit int is not sufficient.
You might get away with using intptr_t to represent the address, and cast using *(double*)valueAddress. But it's still not well-defined.
I'm willing to be corrected on this point but I think the only realistic choice is an inline assembly solution specific to your platform to effect this conversion. That said, you're only reading data from a text file, and you can do that using perfectly normal C++.
First off, int is not the correct data type to store a memory address. You really should use intptr_t from <stdint.h>, which is guaranteed to be the correct size.
To reinterpret this value as a double* and dereference for comparison, you would do:
if ( *(double*)valueAddress < -0.5 )
But I am a little concerned about this. Unless that pointer references memory that already belongs to your program, you are not allowed to access it. Doing so will fall in the realm of undefined behaviour.
You need to dereference your pointer
if ( * ( (double * ) valueAddress ) < -0.5)
This first converts to a pointer, then finds the value pointed to.
My program does the common task of writing binary data to a file, conforming to a certain non-text file format. Since the data I'm writing is not already in existing chunks but instead is put together byte by byte at runtime, I use std::ostream::put() instead of write(). I assume this is normal procedure.
The program works just fine. It uses both std::stringstream::put() and std::ofstream::put() with two-digit hex integers as the arguments. But I get compiler warning C4309: "truncation of constant value" (in VC++ 2010) whenever the argument to put() is greater than 0x7f. Obviously the compiler is expecting a signed char, and the constant is out of range. But I don't think any truncation is actually happening; the byte gets written just like it's supposed to.
Compiler warnings make me think I'm not doing things in the normal, accepted way. The situation I described has to be a common one. Is there are common way to avoid such a compiler warning? Or is this an example of a pointless compiler warning that should just be ignored?
I thought of two inelegant ways to avoid it. I could use syntax like mystream.put( char(0xa4) ) on every call. Or instead of using std::stringstream I could use std::basic_stringstream< unsigned char >, but I don't think that trick would work with std::ofstream, which is not a templated type. I feel like there should be a better solution here, especially since ofstream is meant for writing binary files.
Your thoughts?
--EDIT--
Ah, I was mistaken about std::ofstream not being a templated type. It is actually std::basic_ofstream<char>, but I tried that method that and realized it won't work anyway for lack of defined methods and polymorphic incompatibility with std::ostream.
Here's a code sample:
stringstream ss;
int a, b;
/* Do stuff */
ss.put( 0 );
ss.put( 0x90 | a ); // oddly, no warning here...
ss.put( b ); // ...or here
ss.put( 0xa4 ); // C4309
I found solution that I'm happy with. It's more elegant than explicitly casting every constant to unsigned char. This is what I had:
ss.put( 0xa4 ); // C4309
I thought that the "truncation" was happening in implicitly casting unsigned char to char, but Cong Xu pointed out that integer constants are assumed to be signed, and any one greater than 0x7f gets promoted from char to int. Then it has to actually be truncated (cut down to one byte) if passed to put(). By using the suffix "u", I can specify an unsigned integer constant, and if it's no greater than 0xff, it will be an unsigned char. This is what I have now, without compiler warnings:
ss.put( 0xa4u );
std::stringstream ss;
ss.put(0x7f);
ss.put(0x80); //C4309
As you've guessed, the problem is that ostream.put() expects a char, but 0x7F is the maximum value for char, and anything greater gets promoted to int. You should cast to unsigned char, which is as wide as char so it'll store anything char does and safely, but also make truncation warnings legitimate:
ss.put(static_cast<unsigned char>(0x80)); // OK
ss.put(static_cast<unsigned char>(0xFFFF)); //C4309