将指针转换为整数

Pie*_*BdR 77 c++ 64-bit gcc casting 32-bit

我正在尝试将现有代码调整为64位机器.主要问题是在一个函数中,前一个编码器使用void*参数,该参数在函数本身中转换为合适的类型.一个简短的例子:

void function(MESSAGE_ID id, void* param)
{
    if(id == FOO) {
        int real_param = (int)param;
        // ...
    }
}
Run Code Online (Sandbox Code Playgroud)

当然,在64位机器上,我收到错误:

error: cast from 'void*' to 'int' loses precision
Run Code Online (Sandbox Code Playgroud)

我想纠正这个问题,以便它仍然可以在32位机器上运行并且尽可能干净.任何的想法 ?

Ale*_*lex 79

我会说这是现代的C++方式.

#include <cstdint>
void *p;
auto i = reinterpret_cast<std::uintptr_t>(p);
Run Code Online (Sandbox Code Playgroud)

编辑:

整数的正确类型

所以将指针存储为整数的正确方法是使用uintptr_tintptr_t类型.(另请参阅C99的 cppreference 整数类型).

这些类型在<stdint.h>C99和stdC++ 11 的命名空间中定义<cstdint>(请参阅C++的整数类型).

C++ 11(及以后)版本

#include <cstdint>
std::uintptr_t i;
Run Code Online (Sandbox Code Playgroud)

C++ 03版

extern "C" {
#include <stdint.h>
}

uintptr_t i;
Run Code Online (Sandbox Code Playgroud)

C99版

#include <stdint.h>
uintptr_t i;
Run Code Online (Sandbox Code Playgroud)

正确的铸造操作员

在C中只有一个强制转换,并且在C++中使用C强制转换是不受欢迎的(所以不要在C++中使用它).在C++中有不同的演员阵容.reinterpret_cast是这次转换的正确演员(另见此处).

C++ 11版

auto i = reinterpret_cast<std::uintptr_t>(p);
Run Code Online (Sandbox Code Playgroud)

C++ 03版

uintptr_t i = reinterpret_cast<uintptr_t>(p);
Run Code Online (Sandbox Code Playgroud)

C版

uintptr_t i = (uintptr_t)p; // C Version
Run Code Online (Sandbox Code Playgroud)

相关问题

  • 唯一正确提到reinterpret_cast的答案 (6认同)
  • 这应该被标记为选定的答案,因为它提供了如何在**C和C++**中投射的所有细节. (2认同)

Mil*_*kov 66

使用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
Run Code Online (Sandbox Code Playgroud)

只需将其放在某个.h文件中,并将其包含在您需要的任何位置.

或者,你可以下载微软的版本stdint.h从文件在这里,或者使用从便携式一个在这里.

  • 两个链接都坏了! (2认同)
  • 这个答案与 C 相关,但该语言被标记为 **C++** 所以它不是我想要的答案。 (2认同)

Ric*_*den 41

'size_t'和'ptrdiff_t'需要与您的架构相匹配(无论它是什么).因此,我认为不应该使用'int',而应该能够使用'size_t',它在64位系统上应该是64位类型.

这个讨论unsigned int vs size_t更详细一些.

  • 虽然size_t通常足以容纳指针,但情况并非如此.最好找到一个stdint.h头文件(如果你的编译器还没有),并使用uintptr_t. (34认同)
  • 指针不一定适合`size_t`. (6认同)
  • 不幸的是,`size_t`的唯一约束是它必须保存任何`sizeof()`的结果.这不一定使它在x64上成为64位.[另见](http://stackoverflow.com/a/1089204/762488) (3认同)
  • ``size_t`` *可以* 安全地存储非成员指针的值。请参阅 http://en.cppreference.com/w/cpp/types/size_t。 (3认同)
  • @AndyJost 不,它不能。甚至您自己的链接也证实了这一点。 (2认同)

moo*_*dow 16

使用uintptr_t为您的整数类型.


Jon*_*ler 8

有几个答案指出uintptr_t#include <stdint.h>作为"解决方案".也就是说,我建议,答案的一部分,但不是整个答案.您还需要查看使用FOO的消息ID调用函数的位置.

考虑这段代码和编译:

$ 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
$
Run Code Online (Sandbox Code Playgroud)

您将观察到调用位置(in main())存在问题- 将整数转换为没有强制转换的指针.您将需要分析您function()的所有用法,以了解如何将值传递给它.function()如果写入调用,我的内部代码将起作用:

unsigned long i = 0x2341;
function(1, &i);
Run Code Online (Sandbox Code Playgroud)

由于您的编写方式可能不同,因此需要查看调用函数的点,以确保使用显示的值是有意义的.别忘了,你可能会发现一个潜在的错误.

此外,如果您要格式化void *参数的值(转换后),请仔细查看<inttypes.h>标题(而不是stdint.h- inttypes.h提供服务stdint.h,这是不寻常的,但C99标准说[标题]标题<inttypes.h>包括标题<stdint.h>和通过托管实现提供的附加功能扩展它,并在格式字符串中使用PRIxxx宏.

此外,我的注释严格适用于C而不是C++,但您的代码位于C++的子集中,可以在C和C++之间移植.我的评论适用的机会是公平的.

  • 我想你错过了我的问题.代码将整数的值存储在指针中.并且代码的那部分正在相反(例如,提取被写为*作为*指针的整数的值). (3认同)