如果溢出,i ++是否为小于int的签名类型调用未定义的行为?

时间:2016-10-31 14:01:44

标签: c++ c language-lawyer undefined-behavior

很明显,由于算术溢出,以下代码会调用未定义的行为:

#include <limits.h>

int test(void) {
    int i = INT_MAX;
    i++;  /* undefined behavior */
    return i;
}

但是,intshort之类的签名类型小于signed char呢? (通过较小的,我分别假设SCHAR_MAX < INT_MAXSHRT_MAX < INT_MAX

以下哪个函数会调用未定义的行为?为什么?

signed char test2(void) {
    signed char i = SCHAR_MAX;
    i = i + 1;   /* implementation defined */
    return i;
}

signed char test3(void) {
    signed char i = SCHAR_MAX;
    i += 1;   /* undefined behavior or implementation defined? */
    return i;
}

signed char test4(void) {
    signed char i = SCHAR_MAX;
    i++;      /* undefined behavior or implementation defined? */
    return i;
}

signed char test5(void) {
    signed char i = SCHAR_MAX;
    ++i;      /* undefined behavior or implementation defined? */
    return i;
}

请提供引用或引用C标准以支持您的推理。

2 个答案:

答案 0 :(得分:4)

+=和类似的运算符直接在目标类型的值上运行,并且在许多实现上实际上是他们所做的事情,这是合乎逻辑的。但是,标准要求运营商的行为就像目的地的价值经历任何适用的标准和平衡促销,然后处理指定的操作,然后转换回目的地类型。

因此,如果su是有符号和无符号的16位变量,而int是32位,则s*=s;将为{的所有值定义{1}} [如果结果超过32767,则必须产生实现定义的值或引发实现定义的信号;大多数实现都必须尽力去做除了两个补码减少之外的任何事情。另一方面,s仅保证将值{655}包装为u*=u;,最高为46340;对于较大的值,它将调用未定义的行为。

答案 1 :(得分:0)

以下代码确实导致和溢出,从而导致未定义的行为:

signed char i = SCHAR_MAX;
i++; 

运算符postfix ++不执行整数提升或通常的算术转换 1 。操作符只需将操作数 2 的值加1。操作溢出。

明确区分来自一元算术运算符的措辞:+-~,其措辞清楚地表明操作数被提升 3 < / SUP>。但是对于postfix ++运算符,措辞并没有说运算符被提升 4

显然,postfix ++运算符不会提升操作数。

1 (引自:ISO / IEC 9899:201x 6.3.1.1布尔,字符和整数2 58))
整数促销仅适用于:通常的算术转换的一部分 参数表达式,一元+, - 和〜运算符的操作数,以及两个操作数的操作数 移位运算符,由各自的子条款指定。

2 (引用自:ISO / IEC 9899:201x 6.5.2.4后缀增量和减量运算符2)
作为副作用, 操作数对象的值递增(即,相应类型的值为1 添加到它)

3 (引自:ISO / IEC 9899:201x 6.5.3.3一元算术运算符2)
一元+运算符的结果是其(提升的)操作数的值。整数 在操作数上执行促销,结果具有提升类型。

4 (引自:ISO / IEC 9899:201x 6.5.2.4后缀增量和减量运算符2)
postfix ++运算符的结果是操作数的值。