问题 为什么-Wcast-align没有警告在x86上从char *转换为int *?


我知道gcc有一个选项-Wcast-align,它会在指针被抛出时发出警告,以便增加目标所需的对齐。

这是我的计划:

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

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

为什么我没有收到警告?

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


3271
2017-09-10 09:43


起源

编译器可能会对齐数组并检测它。请尝试使用指针参数,或使用 data+1。 - Medinoc
我认为这是因为你正在投射数组指针。我用数据变量运行代码只是一个char,它完美地给出了警告 - Haris
我把它改成了char * data =“aaaaa”; int ptr = *((int *)data);我仍然没有得到任何警告。我错过了什么? - linuxfreak
为什么你认为x86上指针所需的对齐是8个字节? - Daniel Kamil Kozar
@DanielKamilKozar - 我忽略了这一点 - linuxfreak


答案:


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

首先,让我们看看是什么 gcc的文档 不得不说 -Wcast-align :

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

使用通用指令时,英特尔架构不需要对齐整数。引自 英特尔基础架构手册,第4.1.1节 单词,双字,四字和双四字的对齐 :

单词,双字和四字不需要在内存中对齐   在自然界限上。单词的自然界限,双字,   和四字是偶数地址,地址可以被整除   四分之一,地址分别可被8整除。   但是,要提高程序的性能,数据结构   (特别是堆栈)应该在自然边界上对齐   可能。

因此,尽管强烈建议,但并非严格必要。但是,该规则有一个例外,您可能已经想到了这一点。第18位 EFLAGS 寄存器称为“对齐校验”位,以及第18位 CR0 寄存器称为“对齐掩码”标志。当它们都设置为1时,任何内存访问未在其“自然边界”对齐的数据(因此,对于单词为2个字节,对于双字为4个字节,依此类推)会导致 #AC对齐检查例外。如果您想了解更多相关信息,请查看 英特尔系统编程指南

但是,既不是 适用于i386的System V ABI,也不是 System V ABI for x86-64 指定EFLAGS中的对齐标志已设置。事实上,i386 ABI在第29页第3-3章中注意到以下内容 机器接口 :

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。


14
2017-09-11 19:46



对。它在我使用gcc工具链编译ARM时工作。 - linuxfreak
跟进:是否可以强制警告显示在x86 / x86-64上 无论如何,(交叉编译)? - imallett
@imallett:我在GCC文档中没有找到类似的东西。我想你最好发一个全新的问题。 - Daniel Kamil Kozar
@imallett不在海湾合作委员会,afaik。但是,clang会在任何平台上显示警告。 - Leandros