我已经看到How many usage does "volatile" keyword have in C++ function, from grammar perspective?关于在函数上使用volatile关键字,但没有明确解释该问题的案例1做了什么。只有一位受访者表示这似乎毫无意义/无用。
然而,我不能完全接受这种说法,因为GNUC的AES软件实现已经使用了几年,并且它们有许多这样的功能:
INLINE volatile void functionname( /* ... */ ) {
/* ... */
asm( /* ... */ ) // embedded assembly statements
/* ... */
}
必须有这种用法的原因。任何人都可以:
A 即可。告诉我原来的原因是什么;和
乙即可。现在如何达到预期的效果?
我正在使用Ubuntu和GCC 4.6.3。
<小时/> 注意:我最接近解释的是,在GCC 2.5之前,您可以通过以下方式欺骗在2.5中实现的'noreturn'属性:
void fatal( /* ... */ ) { /* ... */ exit(1); }
typedef void voidfn ();
volatile voidfn fatal;
这将允许编译器识别'致命'不会返回。
但是这种情况似乎不适用于AES代码。自从我在集会上做了很多事以来,已经有很长一段时间了,但我想我会认识到跳跃或类似的事情。
答案 0 :(得分:12)
根据gcc documentation (until February 2015),volatile void
作为C中的函数返回值(但不是在C ++中)等效于函数上的__attribute__((noreturn))
,并告诉编译器函数永远不会返回
答案 1 :(得分:9)
C99标准在§6.7.3/ 3中说明了这一点:
与限定类型关联的属性仅对表达式有意义 是左值。 114)
114)实现可能会将
const
对象放在只读存储区域中volatile
。此外,如果从未使用过地址,则实现不需要为这样的对象分配存储
§6.2.5/ 19说:
void
类型包含一组空值;它是一种不完整的类型 完成。
并且§6.3.2.1/ 1说:
左值是一个对象类型或不完整类型的表达式,而不是
void
; 53) [...]
因此,void
不是左值,因此类型限定符(const
,volatile
和restrict
)对于{{1}类型的表达式没有意义}。因此,在任何符合C99的编译器中,void
和const void
都没有意义(尽管指针到volatile void
和const void
是有意义的。)
此外,§6.9.1/ 3的约束禁止函数返回合格类型的const volatile
:
函数的返回类型应为
void
或数组类型以外的对象类型。
由于这是一个约束,符合标准的编译器必须发出诊断(§5.1.1.3/ 1)。因此,在C99中不允许返回void
的函数。
至于volatile void
可能曾经做过什么,我不知道也无法真正推测。我猜你正在寻找的AES代码可能只是旧版本,我猜是不会被清理干净。
答案 2 :(得分:5)
https://github.com/nmoinvaz/minizip/blob/master/aes/aes_via_ace.h请参阅第323到333行以及第399行到第492行。还有很多其他地方可以找到这段代码,这只是我绊倒的第一个。
http://www.open-std.org/jtc1/sc22/wg14/docs/rr/dr_113.html谢谢@ouah!
http://opencores.org/ocsvn/openrisc/openrisc/trunk/gnu-old/binutils-2.18.50/gas/testsuite/gas/i386/padlock.d打开搜索“f3 0f a7”,并将操作码识别为专门的加密操作。
GCC的“信息”文档。
volatile void function(...)
并非严格符合C99。 (感谢@Adam和@ouah。@Adam深入研究C99规范,以及@ouah将我指向上面列出的DR。)
GCC在版本2.5中添加了__attribute__((noreturn))
作为volatile void
的替代,但是在版本4.6.3中继续接受volatile void
以支持与编译器之前的代码兼容性到版本2.5。 (海湾合作委员会文件。)
上面引用的代码确实将控制权返回到调用它的位置,因为指令似乎没有操纵地址寄存器,也没有执行跳转命令。相反,它们将各种值加载到32位寄存器中。 (代码考试。)
第323到333行中的命令实现了支持加密操作的特殊操作码。 (代码检查加上'挂锁'代码。)
使用汇编函数的代码显然希望它们返回。 (代码考试。)
noreturn
属性告诉编译器函数没有返回,因此编译器可以根据它进行优化。 (海湾合作委员会文件。)
从GCC文档中:在调用noreturn函数之前,不要假设调用函数保存的寄存器已恢复。
与同事讨论最终让我陷入困境。当函数声明它不会返回时,编译器必须做一些不同的事情。对GCC文件的审查证实了这一点。
你需要问自己以下问题。
问题: AES代码专门将值加载到32位寄存器中,并对它们执行操作。 如何将答案返回到其余代码?
答案: GCC优化意味着调用函数的寄存器(否则在返回时会覆盖这些值)不会被保存。汇编语言函数中的计算结果保留在寄存器中,供后续代码使用。
几乎不管它。您唯一可以做的就是用volatile void
替换void
返回类型,并将noreturn
属性添加到函数中。从理论上讲,这应该具有完全相同的效果。在实践中,它没有破坏,不解决它。
绝对不鼓励广泛使用这种技术。首先,它取决于每个编译器的自定义。其次,它取决于那些编译器没有改变他们如何处理“不归”的情况。第三,它可能会让后续的维护者感到困惑。
这种情况的唯一情况是,当你利用高度专业化的机器代码时,要实现速度上不可能的改进。即便如此,也应该平衡权衡利弊。
在此示例中,仅支持两个编译器,并且仅当计算机具有特定的硬件支持才能利用。否则,它全部通过标准C代码处理。这是很多努力。确保它在你做之前付清。