. Advertisement .
..3..
. Advertisement .
..4..
I am tired of fixing the problem: cast from pointer to integer of different size in the c; even if I get the reference from another forum, it still returns an error:
error: cast from pointer to integer of different size [-Werror=pointer-to-int-cast]
To identify the problem, I will show you the detail here:
void* foo(void *dst, ...) {
// some code
unsigned int blkLen = sizeof(int); // this line ok.
unsigned int offset = (unsigned int) dst % blkLen; // warning here!
// some code cont...
}
#if __linux__ // or #if __GNUC__
#if __x86_64__ || __ppc64__
#define ENVIRONMENT64
#else
#define ENVIRONMENT32
#endif
#else
#if _WIN32
#define ENVIRONMENT32
#else
#define ENVIRONMENT64
#endif
#endif // __linux__
#ifdef ENVIRONMENT64
#define MAX_BLOCK_SIZE unsigned long long int
#else
#define MAX_BLOCK_SIZE unsigned long int
#endif // ENVIRONMENT64
unsigned int offset = (MAX_BLOCK_SIZE) dst % blkLen;
How do I do that? Could you support me in improving this problem?
The cause: The compiler is warning you because it thinks you’re trying to round-trip a pointer through int and back. This was typical practice prior to the introduction of 64-bit computers, however it is neither secure nor sensible.
The solution: You’ll need to include
stdint.h
orinttypes.h
to haveuintptr_t
available.Problem is, converting
void*
pointser tounsigned int
is not portable.This is just one aspect of the problem. This part of the problem can easily be solved using
uintptr_t
. It is a type that has been defined in<stdint.h>
or<inttypes.h>
.uintptr_t
is wide enough to ensure that you can convert avoid*
intouintptr_t
and back again to get the original pointer value or at least one that is equal to the original. A typeintptr_t
is also available, which is signed. Usually unsigned types are more appropriate for this type of thing.uintptr_t
andintptr_t
cannot be guaranteed to exist but should exist on any implementation (C99 or later), that uses the appropriate integer types.Even if your integer type is large enough to hold a converted pointeder, it doesn’t necessarily mean that the result will be meaningful for any other purpose than converting back into a pointer.
In a footnote non-normative to the C standard, it states that:
This is useless unless you know the addressing structure.
It seems that you are trying to figure out the offset of
void*
relative toblkLen
‘s next lower multiple. In other words, you want to find out how the pointer value is in relation toblkLen
-sized blocks.It’s okay to decide that it’s sensible to do on your system . However, you need to be aware that operations on integers resulting in pointer conversions are not portable.
One concrete example: I have worked on Cray vector machines, where a
void*
refers to a 64 bit machine address (which points at a 64 bit word), with a 3-bit offset added by software to the high order 3 bits. Simply copy the representation to convert a pointer into an integer. If this representation is not taken into consideration, any integer arithmetic using such an integer will likely yield meaningless results.Conclusions:
uintptr_t
is a better choice than using preprocessor tricks to determine the type of integer you can use. Your compiler’s implementer has already determined an integer type that can safely store a converted pointer value. This is the only way to go. (Caveat –<stdint.h>
was introduced to C in 1999 by the ISO standard. You might need to use#ifdef
hacks if you are stuck with an old compiler that doesn’t implement it. Ifuintptr_t
is available, I recommend it.__STDC_VERSION__ >= 199901L
can be used to check for C99 conformance. However, some compilers may not fully support C99.Converting a pointer into an integer and manipulating its value are not possible. This doesn’t mean you shouldn’t try it. C has the ability to support nonportable codes when you need it.