请考虑以下计划
extern const int foo;
extern void blah(void);
int toto(void) {
int x = foo;
blah();
int y = foo;
return x + y;
}
arm-linux-gnueabihf-gcc -std=c99 -O2 -fno-pic -S extern_const2.c
将其编译为
toto:
@ args = 0, pretend = 0, frame = 0
@ frame_needed = 0, uses_anonymous_args = 0
movw r3, #:lower16:foo
movt r3, #:upper16:foo
push {r4, lr}
ldr r4, [r3]
bl blah
lsls r0, r4, #1
pop {r4, pc}
注意,foo
被读取once,然后被左移1,这意味着gcc
假定它的值在函数调用中保持不变.clang
也观察到了类似的行为.
我看不出ISO/IEC 9899:2017标准的哪一部分明确讨论了这一假设.§6.7.3-12解释了关于extern volatile const
变量的假设(它的值可以由硬件改变,但不能由程序赋值),但这不适用于extern const
.
§6.7.3-6规定程序不能赋值为const
变量.我不太清楚这是否意味着外部调用不能改变这个变量.
此外,第6.7.3-6节的含义对我来说也不是很清楚.上面写着
如果试图通过使用具有非常量限定类型的左值来修改使用常量限定类型定义的对象,则行为是未定义的
然而,在我的示例中,我是declared,而不是defined,foo
是const
.声明和定义的区别在§6.7-5中给出:
声明指定了一组标识符的解释和属性.识别符的定义是对该识别符的声明:-对于对象,使得为该对象保留存储;