我正在使用非常具体的工具链(ADI公司的SHARC DSP处理器),我想更好地了解我的编译器/链接器。
我有一个易变的全局变量:
volatile long foo;
这个变量没有被使用,也没有在我的代码中引用,但是我想把它保存在我的最终可执行文件中(不要问我为什么,这个可悲的事实很难过)。
我通常使用-e
选项链接我的项目。它告诉链接器从可执行文件中删除死代码。我最初认为没有编译器敢于删除任何全局变量,特别是如果这些符号被声明为volatile。不幸的是。
然后我找到了一个非常具体的编译指示#pragma retain_name
,告诉链接器保留一个符号,即使它从未使用过。
我想知道在某些ISO / POSIX标准中是否可以找到这种情况。我总是认为编译器或链接器都不会对易失性符号做出任何假设。因此,没有编译器会尝试从最终的可执行文件中删除死的volatile变量或函数。
我错了吗?
答案 0 :(得分:4)
您可以使用使用变量的外部链接创建虚拟函数。
long
help_us_keep_foo(void)
{
return foo;
}
除非您正在执行整个程序分析,否则将阻止foo
被删除。如果您执行执行整个程序分析,您可以使用如下所示的技巧。
int
main(int argc, char * * argv)
{
if (getenv("PRINT_THE_VALUE_OF_FOO_AT_PROGRAM_STARTUP"))
printf("Your hovercraft is full of eels, and foo is %ld\n", foo);
/* Do whatever your program has to do... */
return 0;
}
我在基准测试代码中使用了类似的技巧(插入无害的打印语句来测试极不可能的条件),以确保我想要基准测试的东西没有被优化掉。
如果情况允许,您可以使用较少的“可见”技巧,例如分配foo = foo
,但由于它是volatile
,我不确定您是否可以安全地执行此操作。
答案 1 :(得分:2)
如果C的一个标准是K& R书,那么关于volatile
没什么好说的,只是提到了几次,据说与优化有关。
在附录A.8.2类型说明符中,它说:
类型也可以是合格的,以表示特殊属性 被宣布的对象。类型限定符: 常量 挥发物 类型限定符可能与任何类型说明符一起出现。一个常数 对象可能已初始化,但此后未分配给。 volatile对象没有与实现相关的语义。常数 和volatile属性是ANSI标准的新特性。的目的 const是宣告可能放在只读内存中的对象, 也许是为了增加优化的机会。 的目的 volatile是强制实现来抑制优化 否则可能会发生。例如,对于具有内存映射的计算机 输入/输出,指向设备寄存器的指针可能被声明为a 指向volatile的指针,以防止编译器被删除 显然是通过指针的冗余引用。 除此之外 应该诊断显式尝试更改const对象,编译器 可能会忽略这些限定符。
强调我的并注意最后一段所说的内容。它可能表明编译器可以选择忽略volatile
限定符。
编译器将允许volatile变量在我的经验中保持未优化,即使它们从未使用过。 我对链接器不太确定。该标准对链接过程的描述很少。
FWIW我对嵌入式目标的商业编译器的一般经验是,他们有时不完全符合标准。我最近一直在使用TI编译器+链接器工具链,让我们说它与我以前用于ARM的gcc + ld端口的情况完全不同,例如...
修改强>
当然,K& R书不是标准。让我们看一下真正的标准,例如:从here获得的ISO C99标准,Section 6.7.3 Type qualifiers, 6
中的一个段落说:
具有volatile限定类型的对象可能会以未知的方式进行修改 实施或有其他未知的副作用。因此任何表达都是指 对这样的对象应严格按照抽象机的规则进行评估, 如5.1.2.3中所述。此外,在每个序列点上最后存储的值 对象应与抽象机器规定的内容一致,除非经过修改 前面提到的未知因素.114)什么构成对对象的访问 volatile的限定类型是实现定义的。
不幸的是,我不认为这有助于回答这个问题。