我正在搜索C90标准,以便在编写高可移植代码时注意事项,同时对编译器供应商的良好意愿缺乏信任,并假设我的软件有时可能会杀死某人,如果我做错了.让我们说我有点偏执.
目前我正在考虑"翻译限制"(5.2.4.1 ANSI/ISO 9899:1990).正如标准中所指出的那样:" ansi C是否限制了程序中外部变量的数量? ",这些是标准符合实现的最低要求.现在另一方面,这意味着,任何实现都不需要做更多 - 如果我想确保我的代码适用于任何confrom实现,这些限制代表我的绝对限制.
到目前为止很烦人.
因此,编译器供应商选择的限制等于或高于最低要求的转换限制.
如果超出特定实施的实施定义的转换限制,现在会发生什么?在我的ANSI/IO 9899:1990(C90)副本中,我没有找到任何东西,所以我认为它是"3种类型的未定义行为"(通过省略).另一方面,这不是第一次,我误解了标准或没有找到正确的段落.
所以这是我的问题:
IS是否超过了C90中特定实现未定义行为的转换限制?
C90行为是否适用于C95/C96以及新迭代C99和C11的修正版本?
有没有人看过那里的检查工具,检查最小的或(工具)用户定义的限制?
1)正如迈克尔·伯尔在对该问题的直接评论中指出的那样,根据C标准(我只检查了没有更正的C90,以及C99草案,Michael 在这里引用),符合C的实现只需要接受一个程序,它同时包含所有限制,在最严格的解释中,它会使任何最小限制保证无效.
2)正如rubenvb和Keith Thompson指出的那样,某些质量的实现应该为案例提供诊断,超出它们的实现定义限制,特别是如果不符合最低要求(rubenvb在评论中链接了MSVC的示例) .
3)由于超出编译器限制可能是未定义的行为,但肯定会导致某些错误,转换限制适用于我的某段代码的"变量"值代表重用的前提条件.
1)因此,对于最大的偏执狂,我会愚弄自己,并惹恼编译器供应商的支持,请求保证我,实现选择的限制适用于任何程序.:-(
2)因此,我将研究编译器文档以及编译器支持获得确认的痛苦程度: - 对于每个转换限制,如果超出,将引发诊断,并且 - 因为它是未定义的行为,如果每个超出翻译限制的实例都会引发诊断 - 或者另一个错误已经阻止了编译.
3)因此,我将尝试开发一个工具(或者如果我真的必须开发自己),测量这些值,并将它们作为我的程序的代码重用的前提条件.正如Keith Thompson在本回答中指出的那样,一些价值观可能需要更深入地了解实施的实施方式.我不能完全确定在这种情况下除了2)中的行为之外还有什么可以帮助的.但是,据我所知,我必须测试 - 但我只需要测试是否有UB(没有诊断),如果是在这种情况下,成功的测试不能保证在一般情况下的正确性.
是的,它是未定义的行为.
Keith Thompson在他的(接受的)anwser中展示了C标准文档的术语和参考,它是未定义的行为.
评论者尚未(尚未)发现检查代码中的事务限制的工具.如果任何具有(甚至部分)此功能的人都会使用该工具,请留下答案或评论.
相关段落可在C90 ISO 9899:1990中找到6.1.2.5类型:
"[..]涉及无符号操作数的计算永远不会溢出,因为[...]"
因此9899:1990 6.3不能适用,因此不能是未定义的行为.
感谢Keith Thompson帮助我阅读.:-)
[2014-03-14]显然无符号短整数可能会溢出,导致未定义的行为,具体取决于目标环境.如果短无符号整数被算术提升为int,则会发生这种情况.详细信息请参阅更新的答案和supercat的评论.感谢两者.:-)
首先,抱歉我的英语不好......我尽我所能.这是我的第一个问题,我认为这是一个非常愚蠢的问题.
由于一些可悲的原因,我的公司仍然坚持ANSI C90(ANSI/ISO 9899:1990),所以我手中有这个标准的旧版本,但仍然缺少更正和修正.
我有一个非常简单的问题,并且在我学习的时候已经完全知道了答案 - 直到我尝试在标准中阅读它.
如果我在添加上有无符号整数溢出会发生什么.请看这段代码:
uint32_t a,b,c;
b = UINT_MAX;
c = UINT_MAX;
a = b + c; /* Overflow here - undefined behavior? */
Run Code Online (Sandbox Code Playgroud)
我所知道的就是,只要需要,无符号整数就会包裹起来,一切都很好,但并非总是如此.
现在我正在寻找标准中的相应部分.
当然,ISO 9899:1990 6.2.1.2描述了无符号整数的转换,无论何时转换.还有一点6.2.1.5"通常的算术转换",它描述了类型如何变得更宽,主要是表达式的两个操作数具有相同的类型.
现在有6.3个"表达式"与我有关.我引用:
"[......]如果在评估表达式期间发生异常(即,如果结果未在数学上定义或不在其类型的可表示的范围内),则行为不明确.[...]"
关于加法运算符的第6.3.6章说:
没有任何说法,结果值被转换为结果类型 - 因此6.2.1.2不适用.但是价值明显溢出,其中6.3步.
据我所知 - 根据ISO 9899:1990,这是未定义的行为.我错过了什么?Corrigendae中有什么东西吗?我错过了标准中的一行或一行吗?
我现在真的很困惑.:-)
关于,马克
[2014-03-03]解决了
[2014-03-03] 感谢Acme我现在对ANSI C99有一个清晰而完整的答案(参见答案: "无符号整数减法定义的行为":明确定义的行为如预期的那样 …
我想广泛使用## - 运算符和枚举魔法来处理大量类似的访问操作,错误处理和数据流.
如果应用##和#预处理器运算符导致无效的pp-token,则行为在C中未定义.
一般情况下,预处理器操作的顺序未在C90中定义(*)(请参阅令牌粘贴操作符).现在在某些情况下,它发生(在不同来源,包括MISRA委员会,以及引用的页面),多个## /# - 运算符的顺序会影响未定义行为的发生.但是我很难理解这些来源的例子并确定共同规则.
所以我的问题是:
有效pp-tokens有哪些规则?
不同的C和C++标准之间有区别吗?
我目前的问题:以下所有2个操作员订单是否合法?(**)
#define test(A) test_## A ## _THING
int test(0001) = 2;
Run Code Online (Sandbox Code Playgroud)评论:
(*)我不使用"未定义",因为这与未定义的行为有关,但恕我直言,而是未指定的行为.应用了多个##或#运算符通常不会使程序错误.显然有一个订单 - 我们无法预测哪个 - 所以订单是未指定的.
(**)这不是编号的实际应用.但模式是等价的.
我计划在我的 C 代码中使用包含标量字段的结构来执行一些语义强类型。基本思想是用于廉价“操作”的宏,这将在错误命名的结构字段上失败,当然还有通过严格参数列表的更复杂的函数。
示例(只有基本思想 - 不是特别聪明的宏代码)
typedef struct {float32_t speedval} MySpeed_t;
typedef struct {float32_t timeval} MyTime_t;
typefed struct {float32_t accvalue} MyAcceleration_t;
#define ACC_VEL_DT(acc,vel,time)\
(((acc).accvalue = (vel).speedval / (time).timeval)), (acc))
#define ADD_SPEED(velres, vel1, vel2) \
(((velres).speedval = (vel1).speedval + (vel2).speedval), (velres))
unint8 someCleverMathAndCheck(MySpeed_t speed, MySpeed_t speedArr[], MyAcceleration_t);
Run Code Online (Sandbox Code Playgroud)
现在,在处理此类 onelement 结构时,我对编译器有何期望?我是否必须期待一些填充,更复杂的 asm 来“取消引用第一个元素”,或者在使用这些构造作为函数参数时出现可怕的事情?标准是怎么说的?
(请参阅"编辑:更新的方案")
这个问题可能是一个或另一个方面的重复,涉及到超出范围的对象指针的未定义行为的大量问题.但我在这里找到的所有问题主要是专门的用例.所以我想把这个问题颠倒过来,不要问是否禁止某些事情,但是究竟允许什么?
有一个可能的场景:你有一个带有指针的函数 - 你不知道它是否来自一个(仍然)有效的对象.在所有情况下哪些操作不是未定义的行为?哪个可能有未指定的副作用?
int * myFunc(const int * const A, int * B)
{
...
}
Run Code Online (Sandbox Code Playgroud)
编辑:更新的方案
在对问题的评论和Matt McNabbs的回答中,有人指出UB最有可能上升,因为在调用场景中的函数期间使用了无效指针(s值).因此,我会稍微改变一下场景(按照Keith Thompsons回答的例子):
int *ptr = malloc(sizeof *ptr);
/* the value of ptr is now valid, possibly NULL */
if (ptr != NULL)
{
/* the value of ptr is valid and non-null */
free(ptr);
/* the value of ptr is now invalid */
... /* here operations in question */
} …Run Code Online (Sandbox Code Playgroud)