假设您知道您的软件只能在两台补码机器上运行,并且可以很好地定义已签名的溢出行为。在C和C ++中,签名溢出仍然是未定义的行为,编译器可以用“ret”替换你的整个程序,开始核战争,格式化你的驱动器,或让恶魔飞出你的鼻子。
假设您已在内联asm中签名溢出,您的程序是否仍会调用UB?
如果是,那么单独编译和链接汇编程序呢?
答案 0 :(得分:8)
“未定义的行为”表示C resp。 C ++标准没有定义程序的行为。如果您的程序包含内联汇编,那么很明显它的行为通常不会被C或C ++标准描述。其他一些标准甚至可能定义行为,但这仍然不代表C或C ++标准上下文中的“定义行为”。
尽管如此,C标准确实需要支持扩展的文档。如果您的程序的行为可以从您的实现文档中推断出来,并且您的实现使您的程序行为不同,那么您的实现将无法符合标准:
<强> 4。一致性强>
8实现应附有一个文档,该文档定义了所有实现定义的和特定于语言环境的特征以及所有扩展。
对于C ++,这个要求被削弱了:
1.4实施合规性[intro.compliance]
9每个实现都应包含标识所有不受支持的条件支持的构造的文档,并定义所有特定于语言环境的特征。
和
1.9程序执行[intro.execution]
2抽象机的某些方面和操作在本国际标准中描述为实施定义[...]每个实施应包括描述其在这些方面的特征和行为的文件。 [...]
我无法找到要求记录扩展的要求,如果记录在案,则需要正确记录。这表明在C ++中,即使你的实现将程序的行为定义为扩展,如果结果证明文档是错误的,那就太糟糕了。
对于C ++半标准asm
语句(如评论中所述,“asm
声明是有条件支持的;其含义是实现定义的。”),如果您的实现支持它它需要记录,但当然,实现以不同于C ++标准暗示的方式支持内联汇编是常见的做法,因此这不会给你额外的贡献。
答案 1 :(得分:2)
只要你说你在内联asm中签名溢出,就意味着你说的是一个特定的编译器(或一组编译器),因为在C ++中,对于asm声明及其含义的支持是< em>编译器定义。
如果编译器通过允许在其输出中直接包含汇编代码来定义asm关键字,并且如果机器允许有符号溢出,则内联asm中的带符号溢出完全定义用于该编译器和该机器:这是处理器将给出的结果。您仍应控制是否可以为有符号整数生成陷阱表示,但无论如何它都是已定义。在UB中结束的唯一情况是编译器表示有符号整数中的某些表示将导致未定义的行为。但是我知道没有这样做,而且你已经处于一组定义的有限的编译器和机器的上下文中。
对于那组编译器和机器,汇编模块和C和/或C ++代码的单独编译将是相同的:结果是实现定义,这与UB不同。
标准(C和C ++)中定义的明确实现的另一个例子是char
类型是否已签名:如果你不知道你使用什么编译器,你就不能依赖它,但一旦选择编译器实现,该实现需要说明它是有符号还是无符号,并且它是不未定义的行为,这意味着编译器无法替换例如,带有ret的完整代码。