将指针转换为整数

我正试图将现有的代码调整到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_tuintptr_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_tintptr_ttypes。 (另请参阅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.hinttypes.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; 

它只应该发出警告。

  1. #include <stdint.h>
  2. 使用包含的标准头文件中定义的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. */ 

信贷交给提​​交者。