将指针转换为整数
我正在尝试将现有代码改编为64位计算机。主要问题在于,在一个函数中,先前的编码器使用void *参数,该参数在函数本身中转换为合适的类型。一个简短的例子:
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位计算机上且尽可能干净地工作。任何的想法 ?
解决方案
使用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文件中,然后在需要的地方添加即可。
或者,我们可以从此处下载Microsoft版本的stdint.h
文件,或者从此处使用可移植的版本。
使用`uintptr_t'作为整数类型。
最好的办法是避免从指针类型转换为非指针类型。
但是,在情况下,这显然是不可能的。
就像每个人都说的那样,我们应该使用uintptr_t。
该链接具有有关转换为64位代码的良好信息。
在comp.std.c上也对此进行了很好的讨论
有几个答案指出了" uintptr_t"和" #include <stdint.h>"作为"解决方案"。我建议,这是答案的一部分,而不是全部答案。我们还需要查看消息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>并将其扩展为
托管实现提供的其他功能),并在格式字符串中使用PRIxxx宏。
另外,我的评论严格适用于C而不是C ++,但是代码位于C ++的子集中,该子集可在C和C ++之间移植。我的评论适用的机会是公平的。
需要" size_t"和" ptrdiff_t"来匹配体系结构(无论它是什么)。因此,我认为我们应该能够使用" size_t",而不是使用" int",它在64位系统上应该是64位类型。
本讨论中的unsigned int vs size_t进行了更详细的介绍。
#include <stdint.h>
- 使用在随附的标准头文件中定义的
uintptr_t
标准类型。