【问题标题】:Why does -Wcast-align not warn about cast from char* to int* on x86?为什么 -Wcast-align 在 x86 上没有警告从 char* 到 int* 的转换?
【发布时间】:2014-11-03 21:51:30
【问题描述】:

我知道 gcc 有一个选项-Wcast-align,它会在指针被强制转换时发出警告,从而增加目标所需的对齐方式。

这是我的程序:

char data[10];
int ptr = *((int *)data);

在我的机器上,数据的对齐要求是 1,而 ptr 的对齐要求是 8。

为什么我没有收到警告?

可能是因为我正在为 x86 编译它吗?

【问题讨论】:

  • 编译器可能会对齐数组并检测到它。尝试使用指针参数,或使用data+1。
  • 我认为这是因为您正在转换数组指针。我用数据变量作为一个字符运行代码,它完美地给出了警告
  • 我把它改成了 char *data = "aaaaa"; int ptr = *((int *)data);我仍然没有得到任何警告。我错过了什么?
  • 为什么你认为在 x86 上指针所需的对齐是 8 个字节?
  • @DanielKamilKozar - 我没抓住重点

标签: c memory-alignment gcc-warning typecasting-operator


【解决方案1】:

2020-05-10 更新: 从 GCC 8 开始,编译器支持选项 -Wcast-align=strict,即使在通常允许未对齐内存访问的目标上也会发出警告。启用它可能是个好主意:the compiler is free to optimise code with the assumption that the pointers are aligned, even on targets that would otherwise not care。


在为 Linux i386 或 x86-64 编译时,在为这些系统使用标准 ABI 时,永远不会发出警告。让我解释一下为什么会这样。

首先,让我们看看gcc's documentation 对-Wcast-align 有什么看法:

每当指针被强制转换时发出警告,使得所需的对齐方式 目标增加。例如,如果 char * 被强制转换为 int * 在只能以二或二访问整数的机器上 四字节边界。

英特尔架构在使用通用指令时不需要整数对齐。引用Intel's Basic Architecture manual,第 4.1.1 章 对齐字、双字、四字和双四字:

字、双字和四字在内存中不需要对齐 在自然边界上。词的自然边界,双词, 和四字是偶数地址,地址可整除 被 4 和地址分别被 8 整除。 然而,为了提高程序的性能,数据结构 (尤其是堆栈)应在自然边界上对齐 可能。

因此,尽管强烈建议对齐,但并非绝对必要。但是,该规则有一个例外,您可能已经想到了。 EFLAGS 寄存器的第 18 位称为“对齐检查”位,CR0 寄存器的第 18 位称为“对齐掩码”标志。当它们都设置为 1 时,对未在其“自然边界”对齐的数据(因此,字 2 字节,双字 4 字节,依此类推)的任何内存访问都会导致 #AC,对齐检查异常。如果您想了解更多信息,请查看Intel System Programming Guide。

但是,System V ABI for i386 和 System V ABI for x86-64 都没有指定设置 EFLAGS 中的对齐标志。事实上,i386 ABI 在第 29 页第 3-3 章 Machine Interface 中记录了以下内容:

Intel386 架构不需要所有的数据访问 正确对齐。 (...) 因此,任意数据访问,例如 指针取消引用或引用参数,可能是也可能不是 正确对齐。访问未对齐的数据会慢于 访问正确对齐的数据,否则没有区别。

虽然它也建议:

编译器应分配具有适当的独立数据对象 对齐。

GCC 总是知道它为其编译代码的平台的 ABI,并且 - 在 x86/64 的情况下 - 知道允许未对齐的数据访问这一事实。这就是为什么这样的代码会在没有对齐警告的情况下编译(让我们忘记以下示例中的严格别名规则):

int main(void)
{
    char foo[] = "foobar";
    int bar = *(int*)(foo + 1);
    return 0;
}

如果您尝试使用 ARM 的 gcc 工具链编译此代码,您将收到警告:

daniel@Jurij:/tmp$ arm-linux-gnueabi-gcc -Wcast-align align.c 
align.c: In function 'main':
align.c:4:13: warning: cast increases required alignment of target type [-Wcast-align]
  int bar = *(int*)(foo + 1);

这是因为在 ARM 中通常最好避免未对齐的访问。我不是 ARM 专家,所以我真的无话可说。

另外,请注意,我写的大部分内容都不适用于 SSE/AVX。

【讨论】:

  • 对。当我使用 ARM 的 gcc 工具链进行编译时,它可以工作。
  • 后续:是否可以强制在x86/x86-64上显示警告反正,(交叉编译不足)?
  • @imallett :我在 GCC 文档中没有找到类似的内容。我想你最好发布一个全新的问题。
  • @imallett 不在 GCC 上,afaik。不过,clang 会在任何平台上显示警告。
  • stackoverflow.com/a/46790815/918959 C 不是它运行的机器架构...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-05
  • 2012-11-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多