C++ 将指针转换为整数

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/153065/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 13:17:38  来源:igfitidea点击:

Converting a pointer into an integer

c++gcccasting64-bit32-bit

提问by PierreBdR

I am trying to adapt an existing code to a 64 bit machine. The main problem is that in one function, the previous coder uses a void* argument that is converted into suitable type in the function itself. A short example:

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

void function(MESSAGE_ID id, void* param)
{
    if(id == FOO) {
        int real_param = (int)param;
        // ...
    }
}

Of course, on a 64 bit machine, I get the error:

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

error: cast from 'void*' to 'int' loses precision

I would like to correct this so that it still works on a 32 bit machine and as cleanly as possible. Any idea ?

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

采纳答案by Milan Babu?kov

Use intptr_tand uintptr_t.

使用intptr_tuintptr_t

To ensure it is defined in a portable way, you can use code like this:

为确保以可移植的方式定义它,您可以使用如下代码:

#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

Just place that in some .h file and include wherever you need it.

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

Alternatively, you can download Microsoft's version of the stdint.hfile from http://msinttypes.googlecode.com/svn/trunk/stdint.h" rel="noreferrer">hereor use a portable one from http://www.azillionmonkeys.com/qed/pstdint.h" rel="noreferrer">here.

或者,你可以下载微软的版本stdint.h从文件http://msinttypes.googlecode.com/svn/trunk/stdint.h" rel="noreferrer">在这里,或者使用从便携式一个http://www.azillionmonkeys.com/qed/pstdint.h" rel="noreferrer">在这里

回答by Alex

I'd say this is the modern C++ way.

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

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

EDIT:

编辑

The correct type to the the Integer

Integer 的正确类型

so the right way to store a pointer as an integer is to use the uintptr_tor intptr_ttypes. (See also in cppreference integer types for C99).

所以将指针存储为整数的正确方法是使用uintptr_torintptr_t类型。(另请参见 cppreference integer types for C99)。

these types are defined in <stdint.h>for C99 and in the namespace stdfor C++11 in <cstdint>(see integer types for C++).

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

C++11 (and onwards) Version

C++11(及以后)版本

#include <cstdint>
std::uintptr_t i;

C++03 Version

C++03版

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

uintptr_t i;

C99 Version

C99版

#include <stdint.h>
uintptr_t i;

The correct casting operator

正确的铸造操作符

In C there is only one cast and using the C cast in C++ is frowned upon (so don't use it in C++). In C++ there is different casts. reinterpret_castis the correct cast for this conversion (See also here).

在 C 中只有一个类型转换,在 C++ 中使用 C 类型转换是不受欢迎的(所以不要在 C++ 中使用它)。在 C++ 中有不同的转换。reinterpret_cast是此转换的正确转换(另请参见此处)。

C++11 Version

C++11 版本

auto i = reinterpret_cast<std::uintptr_t>(p);

C++03 Version

C++03版

uintptr_t i = reinterpret_cast<uintptr_t>(p);

C Version

C版

uintptr_t i = (uintptr_t)p; // C Version

Related Questions

相关问题

回答by Richard Corden

'size_t' and 'ptrdiff_t' are required to match your architecture (whatever it is). Therefore, I think rather than using 'int', you should be able to use 'size_t', which on a 64 bit system should be a 64 bit type.

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

This discussion unsigned int vs size_tgoes into a bit more detail.

这个讨论unsigned int 与 size_t更详细一些。

回答by moonshadow

Use uintptr_tas your integer type.

使用uintptr_t为您的整数类型。

回答by Jonathan Leffler

Several answers have pointed at uintptr_tand #include <stdint.h>as 'the' solution. That is, I suggest, part of the answer, but not the whole answer. You also need to look at where the function is called with the message ID of FOO.

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

Consider this code and compilation:

考虑这个代码和编译:

$ 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
$

You will observe that there is a problem at the calling location (in main()) — converting an integer to a pointer without a cast. You are going to need to analyze your function()in all its usages to see how values are passed to it. The code inside my function()would work if the calls were written:

您将观察到调用位置 (in main())处存在问题— 将整数转换为没有强制转换的指针。您将需要分析您function()的所有用法,以了解值是如何传递给它的。function()如果编写了调用,则my 中的代码将起作用:

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

Since yours are probably written differently, you need to review the points where the function is called to ensure that it makes sense to use the value as shown. Don't forget, you may be finding a latent bug.

由于您的编写方式可能有所不同,因此您需要查看调用函数的位置,以确保使用所示的值是有意义的。不要忘记,您可能会发现一个潜在的错误。

Also, if you are going to format the value of the void *parameter (as converted), look carefully at the <inttypes.h>header (instead of stdint.hinttypes.hprovides the services of stdint.h, which is unusual, but the C99 standard says [t]he header <inttypes.h>includes the header <stdint.h>and extends it with additional facilities provided by hosted implementations) and use the PRIxxx macros in your format strings.

此外,如果您要格式化void *参数的值(转换后),请仔细查看<inttypes.h>标头(而不是stdint.hinttypes.h提供 的服务stdint.h,这是不寻常的,但 C99 标准说[t]he 标头<inttypes.h>包括标头<stdint.h>使用托管实现提供的其他工具对其进行扩展)并在格式字符串中使用 PRIxxx 宏。

Also, my comments are strictly applicable to C rather than C++, but your code is in the subset of C++ that is portable between C and C++. The chances are fair to good that my comments apply.

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

回答by Michael S.

  1. #include <stdint.h>
  2. Use uintptr_tstandard type defined in the included standard header file.
  1. #include <stdint.h>
  2. 使用uintptr_t包含的标准头文件中定义的标准类型。

回答by B.Mr.W.

I came across this question while studying the source code of SQLite.

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

In the sqliteInt.h, there is a paragraph of code defined a macro convert between integer and pointer. The author made a very good statement first pointing out it should be a compiler dependent problem and then implemented the solution to account for most of the popular compilers out there.

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

And here is a quote of the comment for more details:

这是评论的引用以了解更多详细信息:

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

Credit goes to the committers.

归功于提交者。

回答by Craig Hicks

I think the "meaning" of void* in this case is a generic handle. It is not a pointer to a value, it is the value itself. (This just happens to be how void* is used by C and C++ programmers.)

我认为在这种情况下 void* 的“含义”是一个通用句柄。它不是指向值的指针,而是值本身。(这恰好是 C 和 C++ 程序员使用 void* 的方式。)

If it is holding an integer value, it had better be within integer range!

如果是整数值,最好在整数范围内!

Here is easy rendering to integer:

这里很容易渲染为整数:

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

It should only give a warning.

它应该只给出警告。

回答by Benoit

The best thing to do is to avoid converting from pointer type to non-pointer types. However, this is clearly not possible in your case.

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

As everyone said, the uintptr_t is what you should use.

正如大家所说, uintptr_t 是您应该使用的。

This linkhas good info about converting to 64-bit code.

这个链接有关于转换为 64 位代码的好信息。

There is also a good discussion of this on comp.std.c

comp.std.c上也有很好的讨论

回答by Antonio

Since uintptr_tis not guaranteed to be there in C++/C++11, if this is a one way conversion you can consider uintmax_t, always defined in <cstdint>.

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

auto real_param = reinterpret_cast<uintmax_t>(param);

To play safe, one could add anywhere in the code an assertion:

为了安全起见,可以在代码的任何地方添加一个断言:

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