Compiler Depenedent Error with typedef - c++

I am trying to compile my project with different compilers. i have a stable compiled version of the project compiling without any error with the ARM 4.41 compiler. I want to compiler the exactly same source code with the ARM 5 compiler and the Win64 compiler. How ever without any change in the source code, just by switching the compiler from ARM 4.41 to ARM 5 && ARM 4.41 to Win64 i am getting the following error with the typedef's.
I am not able to figure it out, why does it behaves so..?
Header file with typedef's - a_stdtypes.h
#define _STD_TYPE_H
typedef unsigned char bool; // Error #84: invalid combination of type specifiers
typedef unsigned char bit8;
typedef unsigned short bit16;
typedef unsigned long bit32;

This isn't legal C++ code. bool is a reserved keyword of the language - a type. You cannot redefine its meaning. It would be legal C code, though.

I guess it was wrote because someone want to define bool for C, then someone else want to use it from C++.
a neater solution is to use cplusplus macro, like this:
#ifndef __cplusplus
typedef unsigned char bool;
#endif
typedef unsigned char bit8;
typedef unsigned short bit16;
typedef unsigned long bit32;

Related

C++ How to show array element memory address in decimal (instead of hexadecimal)? [duplicate]

I am trying to adapt an existing code to a 64 bit machine. The main problem is that in one function, the previous coder uses a void* argument that is converted into suitable type in the function itself. A short example:
void function(MESSAGE_ID id, void* param)
{
if(id == FOO) {
int real_param = (int)param;
// ...
}
}
Of course, on a 64 bit machine, I get the error:
error: cast from 'void*' to 'int' loses precision
I would like to correct this so that it still works on a 32 bit machine and as cleanly as possible. Any idea ?
I'd say this is the modern C++ way:
#include <cstdint>
void *p;
auto i = reinterpret_cast<std::uintptr_t>(p);
EDIT:
The correct type to the the Integer
So the right way to store a pointer as an integer is to use the uintptr_t or intptr_t types. (See also in cppreference integer types for C99).
These types are defined in <stdint.h> for C99 and in the namespace std for C++11 in <cstdint> (see integer types for C++).
C++11 (and onwards) Version
#include <cstdint>
std::uintptr_t i;
C++03 Version
extern "C" {
#include <stdint.h>
}
uintptr_t i;
C99 Version
#include <stdint.h>
uintptr_t i;
The correct casting operator
In C there is only one cast and using the C cast in C++ is frowned upon (so don't use it in C++). In C++ there are different types of casts, but reinterpret_cast is the correct cast for this conversion (see also here).
C++11 Version
auto i = reinterpret_cast<std::uintptr_t>(p);
C++03 Version
uintptr_t i = reinterpret_cast<uintptr_t>(p);
C Version
uintptr_t i = (uintptr_t)p; // C Version
Related Questions
What is uintptr_t data type
Use intptr_t and uintptr_t.
To ensure it is defined in a portable way, you can use code like this:
#if defined(__BORLANDC__)
typedef unsigned char uint8_t;
typedef __int64 int64_t;
typedef unsigned long uintptr_t;
#elif defined(_MSC_VER)
typedef unsigned char uint8_t;
typedef __int64 int64_t;
#else
#include <stdint.h>
#endif
Just place that in some .h file and include wherever you need it.
Alternatively, you can download Microsoft’s version of the stdint.h file from here or use a portable one from here.
'size_t' and 'ptrdiff_t' are required to match your architecture (whatever it is). Therefore, I think rather than using 'int', you should be able to use 'size_t', which on a 64 bit system should be a 64 bit type.
This discussion unsigned int vs size_t goes into a bit more detail.
Use uintptr_t as your integer type.
Several answers have pointed at uintptr_t and #include <stdint.h> as 'the' solution. That is, I suggest, part of the answer, but not the whole answer. You also need to look at where the function is called with the message ID of FOO.
Consider this code and compilation:
$ cat kk.c
#include <stdio.h>
static void function(int n, void *p)
{
unsigned long z = *(unsigned long *)p;
printf("%d - %lu\n", n, z);
}
int main(void)
{
function(1, 2);
return(0);
}
$ rmk kk
gcc -m64 -g -O -std=c99 -pedantic -Wall -Wshadow -Wpointer-arith \
-Wcast-qual -Wstrict-prototypes -Wmissing-prototypes \
-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE kk.c -o kk
kk.c: In function 'main':
kk.c:10: warning: passing argument 2 of 'func' makes pointer from integer without a cast
$
You will observe that there is a problem at the calling location (in main()) — converting an integer to a pointer without a cast. You are going to need to analyze your function() in all its usages to see how values are passed to it. The code inside my function() would work if the calls were written:
unsigned long i = 0x2341;
function(1, &i);
Since yours are probably written differently, you need to review the points where the function is called to ensure that it makes sense to use the value as shown. Don't forget, you may be finding a latent bug.
Also, if you are going to format the value of the void * parameter (as converted), look carefully at the <inttypes.h> header (instead of stdint.h — inttypes.h provides the services of stdint.h, which is unusual, but the C99 standard says [t]he header <inttypes.h> includes the header <stdint.h> and extends it with
additional facilities provided by hosted implementations) and use the PRIxxx macros in your format strings.
Also, my comments are strictly applicable to C rather than C++, but your code is in the subset of C++ that is portable between C and C++. The chances are fair to good that my comments apply.
#include <stdint.h>
Use uintptr_t standard type defined in the included standard header file.
I came across this question while studying the source code of SQLite.
In the sqliteInt.h, there is a paragraph of code defined a macro convert between integer and pointer. The author made a very good statement first pointing out it should be a compiler dependent problem and then implemented the solution to account for most of the popular compilers out there.
#if defined(__PTRDIFF_TYPE__) /* This case should work for GCC */
# define SQLITE_INT_TO_PTR(X) ((void*)(__PTRDIFF_TYPE__)(X))
# define SQLITE_PTR_TO_INT(X) ((int)(__PTRDIFF_TYPE__)(X))
#elif !defined(__GNUC__) /* Works for compilers other than LLVM */
# define SQLITE_INT_TO_PTR(X) ((void*)&((char*)0)[X])
# define SQLITE_PTR_TO_INT(X) ((int)(((char*)X)-(char*)0))
#elif defined(HAVE_STDINT_H) /* Use this case if we have ANSI headers */
# define SQLITE_INT_TO_PTR(X) ((void*)(intptr_t)(X))
# define SQLITE_PTR_TO_INT(X) ((int)(intptr_t)(X))
#else /* Generates a warning - but it always works */
# define SQLITE_INT_TO_PTR(X) ((void*)(X))
# define SQLITE_PTR_TO_INT(X) ((int)(X))
#endif
And here is a quote of the comment for more details:
/*
** The following macros are used to cast pointers to integers and
** integers to pointers. The way you do this varies from one compiler
** to the next, so we have developed the following set of #if statements
** to generate appropriate macros for a wide range of compilers.
**
** The correct "ANSI" way to do this is to use the intptr_t type.
** Unfortunately, that typedef is not available on all compilers, or
** if it is available, it requires an #include of specific headers
** that vary from one machine to the next.
**
** Ticket #3860: The llvm-gcc-4.2 compiler from Apple chokes on
** the ((void*)&((char*)0)[X]) construct. But MSVC chokes on ((void*)(X)).
** So we have to define the macros in different ways depending on the
** compiler.
*/
Credit goes to the committers.
The best thing to do is to avoid converting from pointer type to non-pointer types.
However, this is clearly not possible in your case.
As everyone said, the uintptr_t is what you should use.
This link has good info about converting to 64-bit code.
There is also a good discussion of this on comp.std.c
I think the "meaning" of void* in this case is a generic handle.
It is not a pointer to a value, it is the value itself.
(This just happens to be how void* is used by C and C++ programmers.)
If it is holding an integer value, it had better be within integer range!
Here is easy rendering to integer:
int x = (char*)p - (char*)0;
It should only give a warning.
Since uintptr_t is not guaranteed to be there in C++/C++11, if this is a one way conversion you can consider uintmax_t, always defined in <cstdint>.
auto real_param = reinterpret_cast<uintmax_t>(param);
To play safe, one could add anywhere in the code an assertion:
static_assert(sizeof (uintmax_t) >= sizeof (void *) ,
"No suitable integer type for conversion from pointer type");
With C++11, For what it's worth, suppose you don't have any headers, then define:
template<bool B, class T, class F> struct cond { typedef T type; };
template<class T, class F> struct cond<false, T, F> { typedef F type;};
static constexpr unsigned int PS = sizeof (void *);
using uintptr_type = typename cond<
PS==sizeof(unsigned short), unsigned short ,
typename cond<
PS==sizeof(unsigned int), unsigned int,
typename cond<
PS==sizeof(unsigned long), unsigned long, unsigned long long>::type>::type>::type;
After that you can do the following:
static uintptr_type ptr_to_int(const void *pointer) {
return reinterpret_cast<uintptr_type>(pointer);
}
static void *int_to_ptr(uintptr_type integer) {
return reinterpret_cast<void *>(integer);
}

Error 2 error C4430: missing type specifier - int assumed. Note: C++ does not support default-int

I am getting these errors
Error 2 error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
Error 2 error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
my code is
#include "stdafx.h"
#include "iostream"
#ifndef uint32_t
#define unsigned int uint32_t;
#endif
struct employee
{
char emp_name[20];
uint32_t emp_id;
};
int _tmain(int argc, _TCHAR* argv[])
{
return 0;
}
what to do on this.
Thanks,
Ravindra Gupta
This is actually a rather interesting error; the error message doesn't do much to tell you what the problem is.
My initial speculation was largely incorrect, but I've left it in place for now. See below.
This code:
#ifndef uint32_t
#define unsigned int uint32_t;
#endif
is incorrect. The name of the macro being defined goes immediately after the #define, and a macro definition normally should not include a semicolon. (Macro definition syntax is quite different from declaration syntax.) Rather than defining uint32_t, this defines unsigned, and attempting to redefine a language keyword can cause serious problems. Also, the #ifndef is not useful, since the uint32_t, if it's defined via "stdafx.h", is a typedef, not a macro. You can use #ifdef UINT32_MAX to check whether `uint32_t has been defined. A correct version is:
#ifndef UINT32_MAX
#define uint32_t unsigned int
#endif
or, even better:
#ifndef UINT32_MAX
typedef unsigned int uint32_t;
#endif
That needs to be fixed, but it didn't cause the problem you're seeing. Apparently uint32_t is not defined in your implementation, causing this declaration:
uint32_t emp_id;
to fail.
The error message is still misleading. Since uint32_t has not been declared, it's treated as an ordinary identifier, not as a type name -- and type names are treated as syntactically distinct from ordinary identifiers. The compiler attempted to recover from the error by guessing that uint32_t might be a member name, which means it should be followed by a semicolon -- but then the declaration
uint32_t;
would declare a member with no explicit type. In old versions of C, this would be legal and would make the member an int. The compiler's guess about what the code actually meant was wrong.
Incidentally, if you show an error message, please tell us which line it applies to.
My initial speculation about the cause of the problem, which turned out to be incorrect follows. I had guessed that _TCHAR was a macro, but it's actually a typedef.
The macro definition:
#ifndef uint32_t
#define unsigned int uint32_t;
#endif
has several levels of wrongness. In a macro definition, the macro being defined goes first, followed by the sequence that it expands to -- which usually should not be terminated by a semicolon:
#define uint32_t unsigned int
But using a macro for this purpose is a bad idea; a typedef is much better:
typedef unsigned int uint32_t;
(note that the identifier being defined goes last, and a semicolon is required; macro definitions and typedefs have very different syntax). And unlike macros, there's no way to test whether a typedef has already been defined.
The uint32_t should already be defined in <stdint.h> or <cstdint> -- but that's a standard header that was added to C by the 1999 ISO C standard, and adopted in C++ only by the 2011 ISO C++ standard, so there's a decent chance that it won't be available, depending on what C++ implementation you're using. If the header exists, you can use #ifdef UINT_MAX to determine whether uint32_t is defined, but that's only useful if you're concerned about systems that don't have a 32-bit unsigned type at all.
But your code doesn't even refer to uint32_t -- so why did the macro definition cause a problem?
Because you got the order wrong, your macro definition doesn't define uint32_t, it defines unsigned, so that any occurrence of that word will expand to int uint32_t; (including the semicolon).
But you don't refer to unsigned either -- at least not directly. The problem, then, is in your definition of _tmain:
int _tmain(int argc, _TCHAR* argv[])
Both _tmain as the program entry point and the type name _TCHAR are Microsoft-specific. I don't have access to a Microsoft compiler at the moment, but judging by the error message you're seeing, _TCHAR (which logically should be a typedef) is probably a macro that expands to something like unsigned short (using a 16-bit type because Windows likes to use 16-bit wide characters for UTF-16).
So your definition:
int _tmain(int argc, _TCHAR* argv[])
expands to:
int _tmain(int argc, unsigned short* argv[])
which, because you've unintentionally redefined unsigned, then expands to:
int _tmain(int argc, int uint32_t; short* argv[])
And since parameter declarations are separated by commas, not by semicolons, this is a syntax error. I'm not sure why this leads to the particular error message you're seeing, but it's not terribly surprising. Syntax errors, particularly those involving incorrectly defined macros, often lead to confusing error messages.
The best strategy for something like this is usually to look at the earliest line on which the compiler reports an error. If the error message itself is not illuminating, ignore it and study the source, trying to figure out what you might have gotten wrong.
If that fails (as it would in this case), try running your program through just the preprocessor. Most Unix-based compilers, including gcc, use a -E option for this; I don't know the corresponding option for Microsoft. The output of the preprocessor is likely to be very verbose (it will include mangled copies of all the headers you include, directly or indirectly), but examining it might lead you to something useful.
In this particular case, commenting out your #define directive would have made the error go away (CORRECTION: no, it wouldn't), which would be a clue that there's something wrong with the #define, even though the relationship between it and the error message is far from obvious.
#define unsigned int uint32_t;
This causes unsigned to be a macro for int uint32_t;, which can't possibly be what you want.
First off, uint32_t is usually a typedef, not a macro. So, even if you have a definition in scope, your #ifdef will do the wrong thing.
Secondly, if you did want to make a macro named uint32_t (which I don't advise), the correct order is:
#define uint32_t unsigned int
However, you are much better off including either <cstdint> if you have it, or <stdint.h> to get a proper definition of uint32_t. (I believe <cstdint> is C++11.)

Typedef redefinition of UInt32 in MacTypes.h, from definition in CFBase.h

I'm getting a typedef redefinition error on two lines in MacTypes.h, in the following chunk of code:
#if __LP64__
typedef unsigned int UInt32;
typedef signed int SInt32;
#else
typedef unsigned long UInt32; // error here
typedef signed long SInt32; // error here
#endif
The Clang error points to the following previous definition, in CFBase.h (in CoreFoundation.framework):
#if !defined(__MACTYPES__)
#if !defined(_OS_OSTYPES_H)
typedef unsigned char Boolean;
typedef unsigned char UInt8;
typedef signed char SInt8;
typedef unsigned short UInt16;
typedef signed short SInt16;
typedef unsigned int UInt32; // previous definition is here
typedef signed int SInt32; // previous definition is here
typedef uint64_t UInt64;
typedef int64_t SInt64;
typedef SInt32 OSStatus;
#endif
...
This is very strange, since __LP64__ is apparently always true on the Mac platform, so why is that typedef even being evaluated? And why is there a path of compilation in which two OS-provided definitions are contradicting each other?
EDIT: Here is a screenshot of the errors in Xcode.
I've blanked out the path of the file that includes <Carbon/Carbon.h> since it contains the name of my client (the file is the same for both errors). The full path names below that are as follows (all contained within Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.sdk/System/Library/Frameworks):
Carbon.framework/Headers/Carbon.h:20
CoreServices.framework/Headers/CoreServices.h:18
CoreServices.framework/Frameworks/AE.framework/Headers/AE.h:20
CoreServices.framework/Frameworks/CarbonCore.framework/Headers/CarbonCore.h:27
CoreServices.framework/Frameworks/CarbonCore.framework/Headers/MacTypes.h:27
Update:
In my own code, just before #include <Carbon/Carbon.h> I've added the following:
#if __LP64__
#error Has LP64
#else
#error Doesn't have LP64
#endif
...and I'm getting the 'Doesn't have LP64' error, so this seems to be the root of the problem. However, when I compile the following in Sublime Text 2 (with SublimeClang)...
int main()
{
#if __LP64__
#error Has LP64
#else
#error Doesn't have LP64
#endif
return 0;
}
...I get "Has LP64". Doing a project text search for #define __LP64__ I can't find anything in my project, and when searching for __LP64__ it just comes up with a load of #ifs and #ifdefs. Does anyone know where this error could have come from?
In the end it turned out this problem was due to multiple installs of Xcode: I had recently installed Xcode 4.4 (from the App Store) and I still had an install of Xcode 3 somewhere. I solved this by running uninstall-devtools which removed Xcode 3, along with all its various paths in the Library and Developer folders. I'm not sure why conflicting installs of Xcode would cause a problem like this, but removing Xcode 3 solved it. I hope this helps anyone who has a problem like this - it's certainly not what I expected the problem to be.

c++ cross platform way to define 64bit unsigned integer

Right now I'm working on a project that extensively uses 64bit unsigned integers in many parts of the code. So far we have only been compiling with gcc 4.6 but we are now porting some code to windows. It's crucial that these unsigned ints are 64bits wide. It has been suggested that we could use long long but it's not good if long long happens to be bigger than 64bits, we actually want to have a guarantee that it will be 64 bits and writing something like static_assert(sizeof(long long) == 8) seems to be a bit of a code smell.
What is the best way to define something like uint64 that will compile across both gcc and msvc without needing to have different code syntax used everywhere?
What about including cstdint and using std::uint64_t?
You can use boost:
The typedef int#_t, with # replaced by the width, designates a signed
integer type of exactly # bits; for example int8_t denotes an 8-bit
signed integer type. Similarly, the typedef uint#_t designates an
unsigned integer type of exactly # bits.
See: http://www.boost.org/doc/libs/1_48_0/libs/integer/doc/html/boost_integer/cstdint.html
Especially this header:
http://www.boost.org/doc/libs/1_48_0/boost/cstdint.hpp
This is what I do:
#ifndef u64
#ifdef WIN32
typedef unsigned __int64 u64;
#else // !WIN32
typedef unsigned long long u64;
#endif
#endif
On Windows you can use __int64, unsigned __int64, or typedefs: UINT64, INT64 etc.
Look at this
But yes, if code portability is concern, use standard typedefs, as suggested by others.

Converting a pointer into an integer

I am trying to adapt an existing code to a 64 bit machine. The main problem is that in one function, the previous coder uses a void* argument that is converted into suitable type in the function itself. A short example:
void function(MESSAGE_ID id, void* param)
{
if(id == FOO) {
int real_param = (int)param;
// ...
}
}
Of course, on a 64 bit machine, I get the error:
error: cast from 'void*' to 'int' loses precision
I would like to correct this so that it still works on a 32 bit machine and as cleanly as possible. Any idea ?
I'd say this is the modern C++ way:
#include <cstdint>
void *p;
auto i = reinterpret_cast<std::uintptr_t>(p);
EDIT:
The correct type to the the Integer
So the right way to store a pointer as an integer is to use the uintptr_t or intptr_t types. (See also in cppreference integer types for C99).
These types are defined in <stdint.h> for C99 and in the namespace std for C++11 in <cstdint> (see integer types for C++).
C++11 (and onwards) Version
#include <cstdint>
std::uintptr_t i;
C++03 Version
extern "C" {
#include <stdint.h>
}
uintptr_t i;
C99 Version
#include <stdint.h>
uintptr_t i;
The correct casting operator
In C there is only one cast and using the C cast in C++ is frowned upon (so don't use it in C++). In C++ there are different types of casts, but reinterpret_cast is the correct cast for this conversion (see also here).
C++11 Version
auto i = reinterpret_cast<std::uintptr_t>(p);
C++03 Version
uintptr_t i = reinterpret_cast<uintptr_t>(p);
C Version
uintptr_t i = (uintptr_t)p; // C Version
Related Questions
What is uintptr_t data type
Use intptr_t and uintptr_t.
To ensure it is defined in a portable way, you can use code like this:
#if defined(__BORLANDC__)
typedef unsigned char uint8_t;
typedef __int64 int64_t;
typedef unsigned long uintptr_t;
#elif defined(_MSC_VER)
typedef unsigned char uint8_t;
typedef __int64 int64_t;
#else
#include <stdint.h>
#endif
Just place that in some .h file and include wherever you need it.
Alternatively, you can download Microsoft’s version of the stdint.h file from here or use a portable one from here.
'size_t' and 'ptrdiff_t' are required to match your architecture (whatever it is). Therefore, I think rather than using 'int', you should be able to use 'size_t', which on a 64 bit system should be a 64 bit type.
This discussion unsigned int vs size_t goes into a bit more detail.
Use uintptr_t as your integer type.
Several answers have pointed at uintptr_t and #include <stdint.h> as 'the' solution. That is, I suggest, part of the answer, but not the whole answer. You also need to look at where the function is called with the message ID of FOO.
Consider this code and compilation:
$ cat kk.c
#include <stdio.h>
static void function(int n, void *p)
{
unsigned long z = *(unsigned long *)p;
printf("%d - %lu\n", n, z);
}
int main(void)
{
function(1, 2);
return(0);
}
$ rmk kk
gcc -m64 -g -O -std=c99 -pedantic -Wall -Wshadow -Wpointer-arith \
-Wcast-qual -Wstrict-prototypes -Wmissing-prototypes \
-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE kk.c -o kk
kk.c: In function 'main':
kk.c:10: warning: passing argument 2 of 'func' makes pointer from integer without a cast
$
You will observe that there is a problem at the calling location (in main()) — converting an integer to a pointer without a cast. You are going to need to analyze your function() in all its usages to see how values are passed to it. The code inside my function() would work if the calls were written:
unsigned long i = 0x2341;
function(1, &i);
Since yours are probably written differently, you need to review the points where the function is called to ensure that it makes sense to use the value as shown. Don't forget, you may be finding a latent bug.
Also, if you are going to format the value of the void * parameter (as converted), look carefully at the <inttypes.h> header (instead of stdint.h — inttypes.h provides the services of stdint.h, which is unusual, but the C99 standard says [t]he header <inttypes.h> includes the header <stdint.h> and extends it with
additional facilities provided by hosted implementations) and use the PRIxxx macros in your format strings.
Also, my comments are strictly applicable to C rather than C++, but your code is in the subset of C++ that is portable between C and C++. The chances are fair to good that my comments apply.
#include <stdint.h>
Use uintptr_t standard type defined in the included standard header file.
I came across this question while studying the source code of SQLite.
In the sqliteInt.h, there is a paragraph of code defined a macro convert between integer and pointer. The author made a very good statement first pointing out it should be a compiler dependent problem and then implemented the solution to account for most of the popular compilers out there.
#if defined(__PTRDIFF_TYPE__) /* This case should work for GCC */
# define SQLITE_INT_TO_PTR(X) ((void*)(__PTRDIFF_TYPE__)(X))
# define SQLITE_PTR_TO_INT(X) ((int)(__PTRDIFF_TYPE__)(X))
#elif !defined(__GNUC__) /* Works for compilers other than LLVM */
# define SQLITE_INT_TO_PTR(X) ((void*)&((char*)0)[X])
# define SQLITE_PTR_TO_INT(X) ((int)(((char*)X)-(char*)0))
#elif defined(HAVE_STDINT_H) /* Use this case if we have ANSI headers */
# define SQLITE_INT_TO_PTR(X) ((void*)(intptr_t)(X))
# define SQLITE_PTR_TO_INT(X) ((int)(intptr_t)(X))
#else /* Generates a warning - but it always works */
# define SQLITE_INT_TO_PTR(X) ((void*)(X))
# define SQLITE_PTR_TO_INT(X) ((int)(X))
#endif
And here is a quote of the comment for more details:
/*
** The following macros are used to cast pointers to integers and
** integers to pointers. The way you do this varies from one compiler
** to the next, so we have developed the following set of #if statements
** to generate appropriate macros for a wide range of compilers.
**
** The correct "ANSI" way to do this is to use the intptr_t type.
** Unfortunately, that typedef is not available on all compilers, or
** if it is available, it requires an #include of specific headers
** that vary from one machine to the next.
**
** Ticket #3860: The llvm-gcc-4.2 compiler from Apple chokes on
** the ((void*)&((char*)0)[X]) construct. But MSVC chokes on ((void*)(X)).
** So we have to define the macros in different ways depending on the
** compiler.
*/
Credit goes to the committers.
The best thing to do is to avoid converting from pointer type to non-pointer types.
However, this is clearly not possible in your case.
As everyone said, the uintptr_t is what you should use.
This link has good info about converting to 64-bit code.
There is also a good discussion of this on comp.std.c
I think the "meaning" of void* in this case is a generic handle.
It is not a pointer to a value, it is the value itself.
(This just happens to be how void* is used by C and C++ programmers.)
If it is holding an integer value, it had better be within integer range!
Here is easy rendering to integer:
int x = (char*)p - (char*)0;
It should only give a warning.
Since uintptr_t is not guaranteed to be there in C++/C++11, if this is a one way conversion you can consider uintmax_t, always defined in <cstdint>.
auto real_param = reinterpret_cast<uintmax_t>(param);
To play safe, one could add anywhere in the code an assertion:
static_assert(sizeof (uintmax_t) >= sizeof (void *) ,
"No suitable integer type for conversion from pointer type");
With C++11, For what it's worth, suppose you don't have any headers, then define:
template<bool B, class T, class F> struct cond { typedef T type; };
template<class T, class F> struct cond<false, T, F> { typedef F type;};
static constexpr unsigned int PS = sizeof (void *);
using uintptr_type = typename cond<
PS==sizeof(unsigned short), unsigned short ,
typename cond<
PS==sizeof(unsigned int), unsigned int,
typename cond<
PS==sizeof(unsigned long), unsigned long, unsigned long long>::type>::type>::type;
After that you can do the following:
static uintptr_type ptr_to_int(const void *pointer) {
return reinterpret_cast<uintptr_type>(pointer);
}
static void *int_to_ptr(uintptr_type integer) {
return reinterpret_cast<void *>(integer);
}