将指针转换为整数
我正试图将现有的代码调整到64位机器。 主要的问题是,在一个函数中,前面的编码器使用一个void *参数,它在函数本身中被转换成合适的types。 一个简短的例子:
void function(MESSAGE_ID id, void* param) { if(id == FOO) { int real_param = (int)param; // ... } }
当然,在64位机器上,我得到的错误是:
error: cast from 'void*' to 'int' loses precision
我想纠正这个问题,使它仍然在32位机器上工作,尽可能干净。 任何想法 ?
'size_t'和'ptrdiff_t'是需要匹配你的架构(不pipe它是什么)。 因此,我认为,而不是使用'int',你应该能够使用'size_t',在64位系统应该是一个64位的types。
这个讨论unsigned int与size_t有一些细节。
使用intptr_t
和uintptr_t
。
为了确保它以便携的方式定义,您可以使用如下代码:
#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
只需将其放在一些.h文件中,并包含所需的任何地方。
另外,你也可以从这里下载微软版本的stdint.h
文件,或者从这里下载一个便携版本。
我会说这是现代C ++的方式。
#include <cstdint> void *p; auto i = reinterpret_cast<std::uintptr_t>(p);
编辑 :
Integer的正确types
因此将指针存储为整数的正确方法是使用uintptr_t
或intptr_t
types。 (另请参阅C99的 cppreference 整数types )。
这些types在<stdint.h>
为C99定义,而在<cstdint>
中定义在C ++ 11的名称空间中(请参阅C ++的整数types )。
C ++ 11(及以上)版本
#include <cstdint> std::uintptr_t i;
C ++ 03版本
extern "C" { #include <stdint.h> } uintptr_t i;
C99版本
#include <stdint.h> uintptr_t i;
正确的铸造操作员
在C中只有一个强制转换,并且在C ++中使用C强制转换(所以不要在C ++中使用它)。 在C ++中有不同的强制转换。 reinterpret_cast
是这种转换的正确模式(另请参见此处 )。
C ++ 11版本
auto i = reinterpret_cast<std::uintptr_t>(p);
C ++ 03版本
uintptr_t i = reinterpret_cast<uintptr_t>(p);
C版本
uintptr_t i = (uintptr_t)p; // C Version
相关问题
- 什么是uintptr_t数据types
使用uintptr_t
作为整数types。
有几个答案指出uintptr_t
和#include <stdint.h>
是“解决scheme”。 也就是说,我build议,答案的一部分,但不是全部的答案。 您还需要查看函数的消息ID为FOO的位置。
考虑这个代码和编译:
$ 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 $
您将观察到在调用位置(在main()
)中存在问题 – 将一个整数转换为一个没有强制转换的指针。 你将需要分析你的function()
的所有用法,看看值是如何传递给它的。 我的function()
的代码将工作,如果调用写入:
unsigned long i = 0x2341; function(1, &i);
由于您的写法可能不同,因此您需要查看函数的调用点,以确保使用所示的值。 不要忘记,你可能会发现一个潜在的错误。
另外,如果你要格式化void *
参数的值(转换后),仔细看看<inttypes.h>
头文件(而不是stdint.h
– inttypes.h
提供了stdint.h
的服务,不寻常的,但是C99标准规定, 头<inttypes.h>
包含头文件<stdint.h>
并通过托pipe实现提供的附加function扩展它 ),并在你的格式string中使用PRIxxxmacros。
此外,我的意见是严格适用于C而不是C ++,但是你的代码是在C和C ++之间可移植的C ++的子集。 我的意见适用的机会是公平的。
我认为在这种情况下void *的“含义”是一个通用的句柄。 它不是一个指向价值的指针,而是价值本身。 (这恰好是C和C ++程序员使用void *的原因。)
如果它是一个整数值,最好在整数范围内!
这里很容易渲染为整数:
int x = (char*)p - (char*)0;
它只应该发出警告。
-
#include <stdint.h>
- 使用包含的标准头文件中定义的
uintptr_t
标准types。
最好的办法是避免从指针types转换为非指针types。 但是,在你的情况下,这显然是不可能的。
正如大家所说,uintptr_t是你应该使用的。
这个链接有关于转换为64位代码的很好的信息。
在comp.std.c上也有很好的讨论
在研究SQLite的源代码时,我遇到了这个问题。
在sqliteInt.h中 ,有一段代码定义了整数和指针之间的macros转换。 作者首先做了一个很好的陈述,指出它应该是一个依赖于编译器的问题,然后实现解决scheme来解释大部分受欢迎的编译器。
#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
这里是更多细节的评论的报价:
/* ** 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. */
信贷交给提交者。