C++ 将指针转换为整数

C++ 将指针转换为整数,c++,gcc,casting,64-bit,32-bit,C++,Gcc,Casting,64 Bit,32 Bit,我正在尝试将现有代码改编为64位机器。主要问题是,在一个函数中,前面的编码器使用void*参数,该参数在函数本身中转换为合适的类型。举个简单的例子: void function(MESSAGE_ID id, void* param) { if(id == FOO) { int real_param = (int)param; // ... } } 当然,在64位机器上,我会得到以下错误: error: cast from 'void*' to '

我正在尝试将现有代码改编为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
uintpr\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
#如果已定义(uu BORLANDC_uu)
typedef无符号字符uint8;
类型定义为int64 int64 t;
typedef无符号长uintptr\t;
#elif已定义(\u MSC\u VER)
typedef无符号字符uint8;
类型定义为int64 int64 t;
#否则
#包括
#恩迪夫
只需将其放在某个.h文件中,并包含在任何需要的地方


或者,您可以从下载Microsoft版本的
stdint.h
文件,或者从中使用便携式文件。

使用
uintptr\t
作为整数类型。

最好避免从指针类型转换为非指针类型。 然而,在你的情况下,这显然是不可能的

正如大家所说,uintptru\t是您应该使用的

这有关于转换为64位代码的好信息


关于这一点也有很好的讨论

一些答案指出,
uintpttr\t
包括
作为“解决方案”。我认为,这是部分答案,但不是全部答案。您还需要查看使用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
$
由于您的函数编写方式可能不同,因此需要查看调用函数的点,以确保使用如图所示的值是合理的。别忘了,你可能发现了一个潜在的bug

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


也可以,我的注释严格适用于C++而不是C++,但是代码是C++的子集,在C和C++之间是可移植的。我的评论很有可能适用。

'size\u t'和'ptrdiff\u t'需要与您的体系结构相匹配(无论是什么)。因此,我认为您应该能够使用“size\u t”,而不是使用“int”,它在64位系统上应该是64位类型

这个讨论更详细一点

  • #包括
  • 使用包含的标准头文件中定义的标准类型
  • 我认为void*在本例中的“含义”是一个通用句柄。 它不是指向值的指针,而是值本身。 (这恰好是C和C++程序员使用的空洞*) 如果它是一个整数值,它最好是在整数范围内

    下面是易于渲染为整数的示例:

    int x = (char*)p - (char*)0;
    

    <>这应该只是一个警告。

    < P>我会说这是现代C++方式。

    #include <cstdint>
    void *p;
    auto i = reinterpret_cast<std::uintptr_t>(p);
    
    C++03版本

    #include <cstdint>
    std::uintptr_t i;
    
    extern "C" {
    #include <stdint.h>
    }
    
    uintptr_t i;
    
    #include <stdint.h>
    uintptr_t i;
    
    auto i = reinterpret_cast<std::uintptr_t>(p);
    
    uintptr_t i = reinterpret_cast<uintptr_t>(p);
    
    uintptr_t i = (uintptr_t)p; // C Version
    
    C++03版本

    #include <cstdint>
    std::uintptr_t i;
    
    extern "C" {
    #include <stdint.h>
    }
    
    uintptr_t i;
    
    #include <stdint.h>
    uintptr_t i;
    
    auto i = reinterpret_cast<std::uintptr_t>(p);
    
    uintptr_t i = reinterpret_cast<uintptr_t>(p);
    
    uintptr_t i = (uintptr_t)p; // C Version
    
    相关问题

    我在研究的源代码时遇到了这个问题

    在中,有一段代码定义了整数和指针之间的宏转换。作者做了一个非常好的陈述,首先指出这应该是一个依赖于编译器的问题,然后实现了解决方案,以解释大多数流行的编译器

    #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.
    */
    

    荣誉归于提交者

    > p> <代码> uutpTrpt>/COD>是,如果这是单向转换,您可以考虑<代码> uTimeMax→< /C>,总是在./p>中定义。
    有关如何获取与MSVC(可能还有Borland)一起工作的stdint.h的信息,请参阅。两个链接都已断开!这个答案与C有关,但是语言被标记为C++,所以它不是我所要寻找的答案。@ HaseBmir一个适当的修复就是切换到<代码> <代码>。或者下载适当的<代码> CSTNDIt <代码>如果下载了<代码> STNET.H./C> > @ HaseBmir,答案是与C相关的唯一原因而不是C++,它使用C报头而不是等效的C++头。C预处理器是C++的一部分, CSTNDRT是C++标准的一部分,所有的类型名称都在这里定义。它确实适用于指定的标记。。。我不同意手动定义类型,但在使用不这样做的编译器时,这可能是必要的。虽然大小通常足以容纳指针,但情况并非如此。最好找到一个stdint.h头(如果您的编译器还没有),并使用uintptr\u t。不幸的是,
    size\u t
    的唯一限制是它必须包含任何
    sizeof()的结果。在x64上,这并不一定是64位
    size\u t
    可以安全地存储非成员指针的值。看。@AndyJost不,它不能。甚至你自己的链接也证实了这一点。@YoYoYonnY:“在许多平台上(分段寻址系统除外),std::size_______________________________________________。代码将整数的值存储在指针中。代码的这一部分做的正好相反(例如,提取作为指针写入的整数的值)。@PierreBdR尽管如此,他还是提出了一个非常有效的观点。查看代码并不总是那么简单(包括编译时)