【问题标题】:How to suppress “warning: cast to pointer from integer of different size”?如何抑制“警告:从不同大小的整数转换为指针”?
【发布时间】:2019-08-13 17:13:39
【问题描述】:

TL;DR:

我需要在我的代码中执行以下操作(非常简化的示例):

int ret = 42;
void * marshaled_ret = (void *) ret;
int unmarshaled_ret = (int) marshaled_ret;

这会导致编译器警告:

警告:从不同大小的整数转换为指针 [-Wint-to-pointer-cast]

我如何才能针对这种特殊情况抑制编译器警告?


背景:我正在围绕特定于平台的多线程库编写一个抽象层。

一个很大的挑战是库期望线程的主函数有不同的签名。 POSIX 有

(void *)(*thread_main)(void *)

而 Windows(实际上)有

int (*thread_main)(void *)

即只有返回类型不同。

因为我需要为所有平台创建一个函数签名,所以我选择了int 作为最受限制的返回类型。在创建线程时,我将用户提供的函数及其参数编组为 struct 并调用包装函数(具有平台预期的签名),然后调用实际的 main 函数。

然而,在 POSIX 上,这涉及将 int 转换为 void * 并返回,如上所示,这会导致编译器警告。

显然,如果您将int 用作指针,则以这种方式将int 转换为指针是一个坏主意(几乎可以保证段错误)。然而,在这种情况下,指针类型只是我的“整数骡子”,从不打算用作指针。

我如何才能针对这种特殊情况抑制编译器警告?

【问题讨论】:

  • 使用uintptr_t 作为中间演员。但是,如果您的int 超出其界限,您将遇到麻烦。
  • "即只有返回类型不同。" - 指针和int 之间的返回类型和字节数也可能不同。 (x64 8字节指针,4字节int)
  • 使ret 成为空指针? void *ret = (void *)42; void * marshaled_ret = ret;
  • 这是最干净的选择,但看在上帝的份上,永远不要尝试并实际使用 ret 作为指针,因为地址 42 将在系统保护内存范围...
  • @KonradRudolph 看起来你误解了我想要达到的目标。转换为intvoid *int,语义上它只是一个任意数字,而不是地址。除非int 比该特定平台上的指针长,否则截断不是问题。

标签: c casting suppress-warnings


【解决方案1】:

在进行两种转换时(int -> void*void* -> int),首先转换为 uintptr_t,然后转换为所需的类型:

int ret = 42;
void *marshaled_return = (void *)(uintptr_t)ret;
int unmarshaled_return = (int)(uintptr_t)marshaled_return;

【讨论】:

  • 问题是 ret 不是指针,可能有不同的类型。为什么不是void *marshaled_return = &ret;,然后是int unmarshaled_return = *((int)marshaled_return);? (除非它被声明为本地)
  • @DavidC.Rankin,他似乎想硬编码一个地址
  • 是的,这有点令人困惑,但如果这是目标,那么使用中间 uniptr 分配该地址将是一种选择......但这更像是一个 baindaid 而不是指向一个解决方案的解决方案更大的设计问题。
  • @DavidC.Rankin:我猜你的意思是*((int*)marshaled_return);,而不是*((int)marshaled_return);
  • 澄清一下:我不打算使用void * 作为指向任何东西的指针。 &ret 将不起作用,因为在我读取地址时该地址可能不再有效。另外,转换为intvoid *int,截断没有意义。
猜你喜欢
  • 2012-11-12
  • 1970-01-01
  • 1970-01-01
  • 2014-02-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-04
相关资源
最近更新 更多