将 int 转换为指针 - 为什么要先转换为 long? (如 p = (void*) 42; )

标签 c pointers casting int long-integer

GLib文档中,有一章是关于类型转换宏的。 在关于将 int 转换为 void* 指针的讨论中,它说(强调我的):

Naively, you might try this, but it's incorrect:

gpointer p;
int i;
p = (void*) 42;
i = (int) p;

Again, that example was not correct, don't copy it. The problem is that on some systems you need to do this:

gpointer p;
int i;
p = (void*) (long) 42;
i = (int) (long) p;

(来源:GLib 2.39.92 的 GLib 引用手册,第 Type Conversion Macros 章)。

为什么必须强制转换为 long

作为指针转换的一部分,int 的任何必需的扩展是否应该自动发生?

最佳答案

glib 文档是错误的,无论是对于他们(自由选择的)示例还是一般情况。

gpointer p;
int i;
p = (void*) 42;
i = (int) p;

gpointer p;
int i;
p = (void*) (long) 42;
i = (int) (long) p;

都将导致相同的值 ip在所有符合标准的 C 实现上。
该示例选择不当,因为 42保证由 int 表示和 long (C11 标准草案 n157:5.2.4.2.1 整数类型的大小)。

一个更具说明性(和可测试性)的例子是

int f(int x)
{
  void *p = (void*) x;
  int r = (int)p;
  return r;
}

这将往返 int -值 iff void*可以表示 int 的每一个值可以,这实际上意味着sizeof(int) <= sizeof(void*) (理论上:填充位,yadda,yadda,实际上并不重要)。对于其他整数类型,同样的问题,同样的实际规则(sizeof(integer_type) <= sizeof(void*))。

相反,真正的问题,适当说明:

void *p(void *x)
{
  char c = (char)x;
  void *r = (void*)c;
  return r;
}

哇,那不可能能行,对吧? (实际上,它可能)。 为了往返一个指针(软件已经不必要地做了很长时间),你必须确保你往返的整数类型可以明确表示指针类型的每个可能值。

从历史上看,许多软件都是由猴子编写的,它们假设指针可以通过 int 往返,可能是因为 K&R c 的隐式 int -“功能”和很多人忘记了#include <stdlib.h>然后转换 malloc() 的结果到一个指针类型,因此不小心通过int往返.在机器上,代码是为 sizeof(int) == sizeof(void*) 开发的,所以这有效。当切换到具有 64 位地址(指针)的 64 位机器时,许多软件期望两个相互排斥的事情:

1) int是一个 32 位 2 的补码整数(通常还期望有符号溢出环绕)
2) sizeof(int) == sizeof(void*)

一些系统(咳咳 Windows 咳咳)也假设sizeof(long) == sizeof(int) , 大多数其他人有 64 位 long .

因此,在大多数系统上,将往返中间整数类型更改为 long修复了(不必要地损坏的)代码:

void *p(void *x)
{
  long l = (long)x;
  void *r = (void*)l;
  return r;
}

除了当然,在 Windows 上。从好的方面来说,对于大多数非 Windows(和非 16 位)系统 sizeof(long) == sizeof(void*)是真的,所以往返工作双向

所以:

  • 示例错误
  • 选择保证往返的类型并不保证往返

当然,c 标准intptr_t 中有一个(自然符合标准的)解决方案|/uintptr_t (C11 标准草案 n1570:7.20.1.4 能够保存对象指针的整数类型)指定以保证
指针 -> 整型 -> 指针
往返(虽然不是相反)。

关于将 int 转换为指针 - 为什么要先转换为 long? (如 p = (void*) 42; ),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25381610/

相关文章:

c - 在相同偏移量的两个整数中快速搜索一些半字节(C,微优化)

无法输出调整后的值

python - 我怎样才能在 C++ 中实现这个结果?数组指向数组

c# - 开箱机制

c++ - casting operator() - 转换为引用并转换为值

openssl 的 C++ 包装器

c - a.out 中的数据部分

c++ - C++ 中的指针和函数

C - 创建动态矩阵函数的问题

java - 查看类型变量是否表示给定类的父类(super class)