我试图去适应现有的码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_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文件中,并将其包含在您需要的任何位置。

或者,您可以从这里或使用这里

其他提示

我会说这是现代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

相关的问题

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

unsigned int vs size_t 的讨论更详细。

使用 uintptr_t 作为整数类型。

有几个答案指出 uintptr_t #include&lt; stdint.h&gt; 为“解决方案”。也就是说,我建议,答案的一部分,但不是整个答案。您还需要查看函数的调用位置,消息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()中)&#8212;将整数转换为没有强制转换的指针。您将需要在其所有用法中分析 function(),以查看如何将值传递给它。如果写入调用, function()中的代码将起作用:

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

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

另外,如果要格式化 void * 参数的值(转换后),请仔细查看&lt; inttypes.h&gt; 标题(而不是 stdint.h &#8212; inttypes.h 提供 stdint.h 的服务,这是不寻常的,但C99标准说< em> [t]标题&lt; inttypes.h&gt; 包含标题&lt; stdint.h&gt; 并将其扩展为 托管实现提供的其他工具)并在格式字符串中使用PRIxxx宏。

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

  1. #include&lt; stdint.h&gt;
  2. 使用随附的标准头文件中定义的 uintptr_t 标准类型。

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

如果它持有一个整数值,最好在整数范围内!

这里很容易渲染为整数:

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

它应该只发出警告。

我在研究 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.
*/

归功于提交者。

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

正如大家所说,你应该使用uintptr_t。

链接信息良好关于转换为64位代码。

comp。对此进行了很好的讨论。 std.c

由于 uintptr_t 不保证在C ++ / C ++ 11中存在,如果这是单向转换,您可以考虑 uintmax_t ,始终在 <代码>&LT; cstdint&GT;

auto real_param = reinterpret_cast<uintmax_t>(param);

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

static_assert(sizeof (uintmax_t) >= sizeof (void *) ,
              "No suitable integer type for conversion from pointer type");
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top