Tag: undefined behavior

未定义的行为:尝试访问函数调用的结果时

以下编译并打印“string”作为输出。 #include struct S { int x; char c[7]; }; struct S bar() { struct S s = {42, “string”}; return s; } int main() { printf(“%s”, bar().c); } 显然,这似乎引发了一个未定义的行为 C99 6.5.2.2/5如果尝试修改函数调用的结果或在下一个序列点之后访问它,则行为未定义。 我不明白它在哪里说“下一个序列点”。 这里发生了什么?

除以零:未定义的行为或实现在C和/或C ++中定义?

关于除零,标准说: C99 6.5.5p5 – /运算符的结果是第一个操作数除以第二个操作数的商; %运算符的结果是余数。 在这两个操作中,如果第二个操作数的值为零,则行为未定义。 C ++ 03 5.6.4 – 二进制/运算符产生商,而二进制%运算符产生第一个表达式除以第二个表达式的余数。 如果/或%的第二个操作数为零,则行为未定义。 如果我们将上述段落视为面值,则答案显然是两种语言的未定义行为 。 但是,如果我们进一步了解C99标准,我们会看到以下段落似乎是矛盾的(1): C99 7.12p4 – 宏INFINITY扩展为float类型的常量表达式,表示正无穷大或无符号无穷大(如果可用); 标准是否有某种黄金法则 ,其中未定义的行为不能被(可能)矛盾的陈述所取代? 除此之外,我认为如果你的实现定义了INFINITY宏,那么除以零被定义为这样是不合理的。 但是,如果您的实现没有定义这样的宏,则行为是Undefined。 我很好奇这两种语言对于这个问题的共识是什么(如果有的话)。 如果我们谈论整数除法int i = 1 / 0 1/0与浮点除法float i = 1.0 / 0.0 ,答案是否会改变? 注意(1) C ++ 03标准讨论了包含INFINITY宏的库。

从未初始化的变量memcpy是未定义的行为吗?

是否使用未初始化的变量作为C中memcpy未定义行为的src ? void foo(int *to) { int from; memcpy(to, &from, sizeof(from)); }

签名右移=奇怪的结果?

我正在帮助某人完成他们的功课,并遇到了这个奇怪的问题。 问题是编写一个函数来反转有符号整数的字节顺序(这就是函数的指定方式),这就是我提出的解决方案: int reverse(int x) { int reversed = 0; reversed = (x & (0xFF <> 24; reversed |= (x & (0xFF <> 8; reversed |= (x & (0xFF << 8)) << 8; reversed |= (x & 0xFF) << 24; return reversed; } 如果将0xFF000000传递给此函数,则第一个赋值将导致0xFFFFFFFF 。 我真的不明白发生了什么,但我知道它与签名和未签名之间的来回转换有关,或类似的东西。 如果我将ul附加到0xFF它工作正常,我认为这是因为它被强制为无符号然后转换为signed或那个方向的东西。 结果代码也会改变; 没有ul说明符它使用sar(右移算术),但是作为无符号它使用shr按预期。 如果有人能为我阐明这一点,我将非常感激。 我应该知道这些东西,我以为我做了,但我真的不确定这里发生了什么。 提前致谢!

序列点和评估顺序

我正在通过K&R阅读,我在评估表达式时遇到了关于行为不确定性的这个例子,如a[i]=i++ ; 6.5美元的C99规格说明了这一点 在前一个和下一个序列点之间,对象的存储值最多只能通过表达式的计算修改一次。 此外,先前的值应该是只读的,以确定要存储的值。 上述K&R的例子在第一个声明中表现良好。 请解释一下如何在第二次失败。 标准是否涉及在涉及序列点的情况下子表达式的评估顺序。 例如。 a[i++] || b[i++] a[i++] || b[i++] 。 我知道这些是从左到右进行评估的,但是如何从上述声明中得出这个或者在标准中明确说明了什么呢?

施放T 到T *

将类型T的2D数组转换为T*并取消引用元素是否安全? 由于2D数组的存储器布局是线性的,因此基指针应该等于指向第一个元素的指针。 由于它们指向的最终类型也是相同的,因此不应存在任何对齐差异问题。 或者有一些方面会导致未定义的行为? 要明确我的意思是这样的 – int arr[10][10]; int p = *((int*) arr); 另外,同样的问题,如果我访问超出第一个数组的元素,即(int *)arr + 13.它是否属于超出界限的条款? 因为我访问第一个数组的边界之外。

是无符号字符 ; 一个 ; 未定义的行为?

来自C标准的未定义行为的示例之一(J.2): – 数组下标超出范围,即使一个对象显然可以使用给定的下标访问(如左边的表达式a [1] [7],给出声明int a [4] [5])(6.5.6) 如果声明从int a[4][5]更改为unsigned char a[4][5] ,访问a[1][7]仍会导致未定义的行为? 我的意见是,它没有,但我从其他人那里听到了不同意见,我想看看其他一些想成为SO专家的想法。 我的推理: 根据6.2.6.1第4段和第6.5段第7段的通常解释,对象a的表示是sizeof (unsigned char [4][5])*CHAR_BIT位,可以作为unsigned char [20]类型的数组访问unsigned char [20]与物体重叠。 a[1]将unsigned char [5]作为左值,但在表达式中使用(作为[]运算符的操作数,或等效地作为*(a[1]+7) +运算符的操作数) ,它衰减到unsigned char *类型的指针。 a[1]值也是指向unsigned char [20]forms的a的“表示”的字节的指针。 以这种方式解释,在a[1]添加7是有效的。

post和pre-increment运算符的以下哪种组合在C中具有未定义的行为?

我读过,有没有人可以解释这些未定义的行为(i = i ++ + ++ i,i = i ++等…)并在浪费超过2小时的时间后尝试理解 “comp.lang.c常见问题解答”中的序列点时间试图通过gcc编译器解释以下结果。 expression(i=1;j=2) ijk k = i++ + j++; 2 3 3 k = i++ + ++j; 2 3 4 k = ++i + j++; 2 3 4 k = ++i + ++j; 2 3 5 k = i++ + i++; 3 2 k = i++ […]

为什么C没有为数组定义最小大小?

C标准定义了许多下限/上限( 转换限制 ),并强制实现应满足每个转换。 为什么没有为数组大小定义这样的最小限制? 以下程序将编译正常并可能产生运行时错误/段错误,并将调用未定义的行为 。 int main() { int a[99999999]; int i; for(i=0;i<99999999;i++) a[i]=i; return 0; } 可能的原因可能是在自动存储上分配了本地数组,它取决于分配的堆栈帧的大小。 但为什么不像C定义的其他限制那样达到最小限度? 让我们忘记上面提到的未定义的情况。 考虑以下: int main() { int a[10]; int i; for(i=0;i<10;i++) a[i]=i; return 0; } 在上面,是什么让我保证本地数组(尽管非常小)将按预期工作,并且不会因分配失败而导致未定义的行为? 虽然这种小型arrays的分配不太可能在任何现代系统上失败。 但是C标准没有定义满足要求,编译器也没有(至少GCC没有)报告分配失败。 只有运行时错误/未定义的行为才有可能。 困难的部分是没有人能够判断任意大小的数组是否会因分配失败而导致未定义的行为。 请注意,我知道我可以使用动态数组(通过malloc和朋友)来实现此目的,并可以更好地控制分配失败。 我更感兴趣的是为什么没有为本地数组定义这样的限制。 此外,全局数组将存储在静态存储中,并将增加编译器可以处理的可执行文件大小。

表达式中有序列点a ^ = b ^ = a ^ = b,还是未定义?

据称“巧妙”(但实际上效率低下)交换两个整数变量而不是使用临时存储的方式通常涉及这一行: int a = 10; int b = 42; a ^= b ^= a ^= b; /*Here*/ printf(“a=%d, b=%d\n”, a, b); 但我想知道,复合赋值运算符如^=不是序列点,是吗? 这是否意味着它实际上是未定义的行为?