小编Mar*_* A.的帖子

超出翻译限制是不确定的行为,是否有检查工具来找到它?

原始问题:

我正在搜索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)正如rubenvbKeith Thompson指出的那样,某些质量的实现应该为案例提供诊断,超出它们的实现定义限制,特别是如果不符合最低要求(rubenvb在评论中链接了MSVC的示例) .

3)由于超出编译器限制可能是未定义的行为,但肯定会导致某些错误,转换限制适用于我的某段代码的"变量"值代表重用的前提条件.

我的个人策略来处理它们

1)因此,对于最大的偏执狂,我会愚弄自己,并惹恼编译器供应商的支持,请求保证我,实现选择的限制适用于任何程序.:-(

2)因此,我将研究编译器文档以及编译器支持获得确认的痛苦程度: - 对于每个转换限制,如果超出,将引发诊断,并且 - 因为它是未定义的行为,如果每个超出翻译限制的实例都会引发诊断 - 或者另一个错误已经阻止了编译.

3)因此,我将尝试开发一个工具(或者如果我真的必须开发自己),测量这些值,并将它们作为我的程序的代码重用的前提条件.正如Keith Thompson在本回答中指出的那样,一些价值观可能需要更深入地了解实施的实施方式.我不能完全确定在这种情况下除了2)中的行为之外还有什么可以帮助的.但是,据我所知,我必须测试 - 但我只需要测试是否有UB(没有诊断),如果是在这种情况下,成功的测试不能保证在一般情况下的正确性.

回答说:

是的,它是未定义的行为.

Keith Thompson在他的(接受的)anwser中展示了C标准文档的术语和参考,它是未定义的行为.

评论者尚未(尚未)发现检查代码中的事务限制的工具.如果任何具有(甚至部分)此功能的人都会使用该工具,请留下答案或评论.

c standards standards-compliance c89 undefined-behavior

12
推荐指数
1
解决办法
859
查看次数

C90中无符号整数加法和未定义行为

解决了!

相关段落可在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章说:

  • 对操作数的通常算术转换,不适用于所有内容都是uint32_t.
  • 结果是两者的总和,显然不适合uint32_t.
  • 精细

没有任何说法,结果值被转换为结果类型 - 因此6.2.1.2不适用.但是价值明显溢出,其中6.3步.

据我所知 - 根据ISO 9899:1990,这是未定义的行为.我错过了什么?Corrigendae中有什么东西吗?我错过了标准中的一行或一行吗?

我现在真的很困惑.:-)

关于,马克

问题更新

[2014-03-03]解决了

[2014-03-03] 感谢Acme我现在对ANSI C99有一个清晰而完整的答案(参见答案: "无符号整数减法定义的行为":明确定义的行为如预期的那样 …

c standards c89 undefined-behavior unsigned-integer

5
推荐指数
1
解决办法
1058
查看次数

有效和无效pp-tokens的定义是什么?

我想广泛使用## - 运算符和枚举魔法来处理大量类似的访问操作,错误处理和数据流.

如果应用###预处理器运算符导致无效的pp-token,则行为在C中未定义.

一般情况下,预处理器操作的顺序未在C90中定义(*)(请参阅令牌粘贴操作符).现在在某些情况下,它发生(在不同来源,包括MISRA委员会,以及引用的页面),多个## /# - 运算符的顺序会影响未定义行为的发生.但是我很难理解这些来源的例子并确定共同规则.

所以我的问题是:

  1. 有效pp-tokens有哪些规则?

  2. 不同的C和C++标准之间有区别吗?

  3. 我目前的问题:以下所有2个操作员订单是否合法?(**)

    #define test(A) test_## A ## _THING
    int test(0001) = 2;
    
    Run Code Online (Sandbox Code Playgroud)

评论:

(*)我不使用"未定义",因为这与未定义的行为有关,但恕我直言,而是未指定的行为.应用了多个##或#运算符通常不会使程序错误.显然有一个订单 - 我们无法预测哪个 - 所以订单是未指定的.

(**)这不是编号的实际应用.但模式是等价的.

c c++ c89 c-preprocessor

3
推荐指数
1
解决办法
1256
查看次数

“强”通过单元素结构在 C 中键入。编译器会做什么?

我计划在我的 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 来“取消引用第一个元素”,或者在使用这些构造作为函数参数时出现可怕的事情?标准是怎么说的?

c struct padding strong-typing c89

1
推荐指数
1
解决办法
143
查看次数

通过严格解释C标准允许对可能无效的指针进行操作

原始问题

(请参阅"编辑:更新的方案")

这个问题可能是一个或另一个方面的重复,涉及到超出范围的对象指针的未定义行为的大量问题.但我在这里找到的所有问题主要是专门的用例.所以我想把这个问题颠倒过来,不要问是否禁止某些事情,但是究竟允许什么?

有一个可能的场景:你有一个带有指针的函数 - 你不知道它是否来自一个(仍然)有效的对象.在所有情况下哪些操作不是未定义的行为?哪个可能有未指定的副作用?

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)

c pointers c89 undefined-behavior

1
推荐指数
1
解决办法
152
查看次数