【问题标题】:Converting a pointer to different type in C在C中将指针转换为不同的类型
【发布时间】:2012-11-21 16:25:20
【问题描述】:
int i = 42;
int *p1 = &i;
int long *p2 = (long*)p1;

这是未定义的行为吗?在 C++ 中,出于某种原因,我认为这是实现定义的行为。

我查看了 C 标准:

C99 6.3.2.3/7 指向对象或不完整类型的指针可能是 转换为指向不同对象或不完整类型的指针。如果 结果指针未正确对齐 57) 对于指向 类型,行为未定义。否则,当再次转换回来时, 结果应与原始指针比较。

57) 一般来说,“正确对齐”的概念是可传递的:如果 指向类型 A 的指针与指向类型 B 的指针正确对齐,这 依次正确对齐指向 C 类型的指针,然后是指针 到类型 A 的指针与指向类型 C 的指针正确对齐。

“正确对齐”一词在实践中是什么意思?在不进入未定义行为的情况下,您如何知道自己是否正确执行了操作?

【问题讨论】:

  • 如果您取消引用 p2,这是未定义的行为。原因:你违反了严格别名。
  • int long *p2???这里有什么长的?
  • 在 32bit arch 上,sizeof(int) == sizeof(long),所以没有区别。在 64 上 - 你会在 long 的另一半有一些垃圾,或者甚至可能留下分配的内存区域,所以再一次 - 没有必要这样做。除此之外,它是正确的。
  • @Krishnabhadra:int long *p2 是一种合法但略显非正统的写作方式signed long int *p2long *p2long int *p2long int signed *p2(这些都是等价的)。跨度>
  • 在 RISC 机器上的 64 位环境中,i 很有可能在奇数 32 位地址边界上对齐,但 long 必须在 64 位地址上对齐边界(甚至 32 位地址边界)。因此,在此类系统上,如果您尝试通过p2 读取或修改内存,您将获得 SIGBUS。

标签: c type-conversion c99


【解决方案1】:

这基本上意味着,如果int 对齐到 4 个字节,int long 对齐到 8 个字节,则行为未定义。假设你有类似的东西:

 0x04     0x08    0x0C    0x10
+------+-------+-------+-------+
|      |       |   i   |       |
+------+-------+-------+-------+

在这种情况下,&i == 0x0C(这是有效的,因为int 对齐到 4 个字节)。当您转换为 int long* 时,指针将转换为对齐的:p2 == 0x08,因为我们的理论系统将 int long 对齐到 8 个字节,所以如果您基本上读取了一个您不拥有的地址取消引用p1,因此未定义的行为。

【讨论】:

  • 所以,基本上如果两个指针类型的 sizeof 不一样,比如 sizeof int 和 sizeof long 不相等,那么你会得到未定义的行为,对吧?
  • @user963241 AFAIK,对齐方式和大小并不总是相同的。我建议不要这样做。为什么你还需要?
  • 只是好奇在指针类型之间转换时导致未定义行为的原因。感谢您的建议。
  • sizeof(int *) == sizeof(long *) — 指针大小相同。但对齐要求不一定相同。在 RISC 芯片(不是 Intel)上,N 字节类型(N = 1、2、4、8)应在 N 字节边界上对齐。英特尔不会强制执行此操作(但如果您使用未对齐的指针,则会降低性能)。
  • 我可以检查 gcc 中类型的对齐要求吗?
猜你喜欢
  • 2021-09-20
  • 2023-04-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-17
  • 1970-01-01
  • 2020-06-01
相关资源
最近更新 更多