这可能是GCC中的一个bug。
首先,需要注意的是,您的代码违反了严格别名规则,因此会引起未定义行为。
话虽如此,我认为这是一个bug的原因是:
当该表达式首次赋值给一个中间的short
或short *
时,会产生预期的行为。只有在将表达式直接作为函数参数传递时,才会出现意外的行为。
即使使用-O0 -fno-strict-aliasing
编译,也会发生此情况。
我用C重新编写了您的代码,以消除任何C++的疯狂行为可能性。毕竟,您的问题是曾经被标记为c
!我添加了pshort
函数以确保不涉及可变参数性质的printf
。
#include <stdio.h>
static void pshort(short val)
{
printf("0x%hx ", val);
}
int main(void)
{
short A[] = {1, 2, 3, 4, 5, 6};
#define EXP ((short*)((char*)A + 7))
short *p = EXP;
short q = *EXP;
pshort(*p);
pshort(q);
pshort(*EXP);
printf("\n");
return 0;
}
使用 gcc (GCC) 7.3.1 20180130 (Red Hat 7.3.1-2)
编译后:
gcc -O0 -fno-strict-aliasing -g -Wall -Werror endian.c
输出:
0x500 0x500 0x4
看起来当表达式直接用作参数时,GCC实际上正在生成不同的代码,尽管我明显在使用相同的表达式(EXP
)。
使用objdump -Mintel -S --no-show-raw-insn endian
进行转储:
int main(void)
{
40054d: push rbp
40054e: mov rbp,rsp
400551: sub rsp,0x20
short A[] = {1, 2, 3, 4, 5, 6}
400555: mov WORD PTR [rbp-0x16],0x1
40055b: mov WORD PTR [rbp-0x14],0x2
400561: mov WORD PTR [rbp-0x12],0x3
400567: mov WORD PTR [rbp-0x10],0x4
40056d: mov WORD PTR [rbp-0xe],0x5
400573: mov WORD PTR [rbp-0xc],0x6
#define EXP ((short*)((char*)A + 7))
short *p = EXP
400579: lea rax,[rbp-0x16]
40057d: add rax,0x7
400581: mov QWORD PTR [rbp-0x8],rax
short q = *EXP
400585: movzx eax,WORD PTR [rbp-0xf]
400589: mov WORD PTR [rbp-0xa],ax
pshort(*p)
40058d: mov rax,QWORD PTR [rbp-0x8]
400591: movzx eax,WORD PTR [rax]
400594: cwde
400595: mov edi,eax
400597: call 400527 <pshort>
pshort(q)
40059c: movsx eax,WORD PTR [rbp-0xa]
4005a0: mov edi,eax
4005a2: call 400527 <pshort>
pshort(*EXP)
4005a7: movzx eax,WORD PTR [rbp-0x10]
4005ab: cwde
4005ac: mov edi,eax
4005ae: call 400527 <pshort>
printf("\n")
4005b3: mov edi,0xa
4005b8: call 400430 <putchar@plt>
return 0
4005bd: mov eax,0x0
}
4005c2: leave
4005c3: ret
- 我使用来自Docker Hub的GCC 4.9.4和GCC 5.5.0得到了相同的结果
memcpy()
到一个short
中,然后输出该值。 - Ulrich Eckhardtg++ 5.4.1-2
- Jacek Skiba