转换一个指针到一个整数(Converting a pointer into an integer)

2019-07-21 06:04发布

我想现有的代码适应64位机。 的主要问题是,在一个功能,以前的编码器使用被转换成适当的类型的函数本身的空隙*参数。 简单例子:

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位计算机上,并尽可能干净。 任何的想法 ?

Answer 1:

使用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从文件在这里 ,或者使用从便携式一个在这里 。



Answer 2:

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

#include <cstdint>
void *p;
auto i = reinterpret_cast<std::uintptr_t>(p);

编辑

正确类型的整数

所以,用于存储指针为一个整数以正确的方式是使用uintptr_tintptr_t类型。 (也可参见cppreference 整数类型为C99 )。

这些类型中所定义<stdint.h>用于C99和命名空间中的std用于C ++ 11 <cstdint>参见整数类型为C ++ )。

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的数据类型


Answer 3:

“为size_t”和“ptrdiff_t的”必须符合你的架构(不管它是什么)。 因此,我认为不是使用“廉政”,你应该能够使用“的size_t”,它在64位系统上应该是一个64位的类型。

这个讨论unsigned int类型VS为size_t进入一些详细信息。



Answer 4:

使用uintptr_t为您的整数类型。



Answer 5:

几个答案已经指出在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
$

你会发现,有向主叫位置的问题(在main() -转换为指针的整数,未作演员。 你将需要分析你的function()在其所有的用法,看值是如何传递给它。 我里面的代码function() ,如果调用写会工作:

unsigned long i = 0x2341;
function(1, &i);

因为你很可能有不同的写法,你需要检查在函数被调用,以确保有意义的使用值如图所示的点。 不要忘了,你可能会发现潜在的bug。

此外,如果你要格式化的值void *参数(如转换),仔细看一下<inttypes.h>报头(而不是stdint.h - inttypes.h提供的服务stdint.h ,这是不寻常的,但C99标准说[T]他首部<inttypes.h>包含头<stdint.h>和与托管的实现提供了额外的设施将其扩展 ),并且在格式字符串使用PRIxxx宏。

另外,我的意见是严格适用到C而不是C ++,但你的代码是在C ++的子集是C和C ++之间进行移植。 机会是公平的很好,我的意见适用。



Answer 6:

  1. #include <stdint.h>
  2. 使用uintptr_t在附带的标准头文件中定义的标准类型。


Answer 7:

我认为,在这种情况下无效*的“意义”是一个通用的句柄。 它不是一个指针的值,它本身的价值。 (这恰好是如何void *的是使用C和C ++程序员。)

如果是抱着一个整数值,它最好是整数的范围之内!

这是很容易渲染整数:

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

它应该只给予警告。



Answer 8:

我碰到这个问题就来了,而学习的源代码的SQLite 。

在sqliteInt.h ,存在定义的整数和指针之间的宏转换的代码的一个段落。 笔者做了一个非常优秀的报表首先指出它应该是一个编译器相关的问题,然后实施解决占大多数流行的编译器在那里。

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

幸得提交者。



Answer 9:

做的最好的事情是为了避免指针类型转换到非指针类型。 但是,这显然不是你的情况可能。

正如大家所说,uintptr_t的是你应该用什么。

此链接有大约转换为64位代码好信息。

还有的这一个良好的讨论comp.std.c



Answer 10:

由于uintptr_t是不能保证有在C ++ / C ++ 11 ,如果这是一个单向转换可以考虑uintmax_t ,总是在定义<cstdint>

auto real_param = reinterpret_cast<uintmax_t>(param);

为了稳妥起见,人们可以在代码中断言的任意位置添加:

static_assert(sizeof (uintmax_t) >= sizeof (void *) ,
              "No suitable integer type for conversion from pointer type");


文章来源: Converting a pointer into an integer