Questions tagged «undefined-behavior»

编译或执行程序的不可预测结果破坏了编译器,解释器或运行时系统都不必执行的语言规则。请勿对数据类型或返回值“ undefined”的问题使用此标记。在这些情况下,应改用[undefined]标签。


2
什么时候在空实例上调用成员函数会导致未定义的行为?
考虑以下代码: #include <iostream> struct foo { // (a): void bar() { std::cout << "gman was here" << std::endl; } // (b): void baz() { x = 5; } int x; }; int main() { foo* f = 0; f->bar(); // (a) f->baz(); // (b) } 我们预期(b)会崩溃,因为xnull指针没有对应的成员。实际上,(a)不会崩溃,因为this从未使用过指针。 因为(b)取消引用this指针((*this).x = 5;),并且this为null,所以程序将输入未定义的行为,因为始终将取消引用null视为未定义的行为。 会(a)导致不确定的行为吗?如果两个函数(和x)都是静态的怎么办?

9
我如何从一个8位整数中得到一个大于8位的值?
我找到了隐藏在这个小宝石后面的极其讨厌的错误。我知道,按照C ++规范,带符号的溢出是未定义的行为,但是只有当值扩展到bit-width时才发生溢出sizeof(int)。据我了解,增加a char永远不会是未定义的行为sizeof(char) < sizeof(int)。但这并不能解释如何c获得不可能的价值。作为8位整数,如何c保存大于其位宽的值? 码 // Compiled with gcc-4.7.2 #include <cstdio> #include <stdint.h> #include <climits> int main() { int8_t c = 0; printf("SCHAR_MIN: %i\n", SCHAR_MIN); printf("SCHAR_MAX: %i\n", SCHAR_MAX); for (int32_t i = 0; i <= 300; i++) printf("c: %i\n", c--); printf("c: %i\n", c); return 0; } 输出量 SCHAR_MIN: -128 …

8
“结构骇客”在技术上是不确定的行为吗?
我要问的是众所周知的“结构的最后一个成员具有可变长度”的技巧。它是这样的: struct T { int len; char s[1]; }; struct T *p = malloc(sizeof(struct T) + 100); p->len = 100; strcpy(p->s, "hello world"); 由于结构在内存中的布局方式,我们能够将结构覆盖在大于必要的块上,并将最后一个成员视为大于1 char指定的成员。 所以问题是:这项技术在技术上是否是未定义的行为?。我希望是这样,但是很好奇标准对此表示了什么。 PS:我知道使用C99的方法,我希望答案特别遵循上面列出的技巧。

2
在C ++ 20之前将malloc用于int未定义行为
有人告诉我,以下代码在C ++ 20之前具有未定义的行为: int *p = (int*)malloc(sizeof(int)); *p = 10; 真的吗? 该论点是int对象的生存期在分配值之前没有开始(P0593R6)。若要解决此问题,new应使用放置: int *p = (int*)malloc(sizeof(int)); new (p) int; *p = 10; 我们真的必须调用一个琐碎的默认构造函数来启动对象的生存期吗? 同时,该代码在纯C语言中没有未定义的行为。但是,如果我int在C代码中分配一个并在C ++代码中使用它会怎样? // C source code: int *alloc_int(void) { int *p = (int*)malloc(sizeof(int)); *p = 10; return p; } // C++ source code: extern "C" int *alloc_int(void); …


8
可以将具有未定义行为的分支视为不可达并优化为死代码吗?
考虑以下语句: *((char*)NULL) = 0; //undefined behavior 它显然会调用未定义的行为。给定程序中存在这样的语句是否意味着整个程序是未定义的,或者行为仅在控制流命中该语句后才变为未定义? 如果用户从不输入数字,以下程序是否定义明确3? while (true) { int num = ReadNumberFromConsole(); if (num == 3) *((char*)NULL) = 0; //undefined behavior } 还是无论用户输入什么,都是完全不确定的行为? 另外,编译器可以假定未定义的行为永远不会在运行时执行吗?这将允许往后倒推: int num = ReadNumberFromConsole(); if (num == 3) { PrintToConsole(num); *((char*)NULL) = 0; //undefined behavior } 在这里,编译器可能会推断出万一num == 3我们总是调用未定义的行为。因此,这种情况必须是不可能的,并且不需要打印号码。整个if语句可以优化。根据标准是否允许这种向后推理?

10
为什么printf(“%f”,0); 给未定义的行为?
该声明 printf("%f\n",0.0f); 打印0。 但是,声明 printf("%f\n",0); 打印随机值。 我意识到我表现出某种不确定的行为,但我不知道具体为什么。 所有位均为0的浮点值仍然是有效的float,值为0。 float并且int在我的计算机上具有相同的大小(如果相关)。 为什么使用整数文字而不是浮点文字printf会导致此行为? PS如果我使用可以看到相同的行为 int i = 0; printf("%f\n", i);

12
在循环中的什么时候整数溢出会变成未定义的行为?
这是一个示例来说明我的问题,其中涉及一些我无法在此处发布的更复杂的代码。 #include <stdio.h> int main() { int a = 0; for (int i = 0; i < 3; i++) { printf("Hello\n"); a = a + 1000000000; } } 该程序在我的平台上包含未定义的行为,因为a它将在第3个循环中溢出。 这是否会使整个程序具有未定义的行为,还是仅在实际发生溢出之后?编译器是否可以解决a 将导致溢出的问题,以便它可以声明整个循环未定义,并且即使它们都在溢出之前发生,也不必费心运行printfs? (尽管标记为C和C ++有所不同,但如果它们不相同,我会对两种语言的答案都感兴趣。)

3
包含未定义行为的源代码会使编译器崩溃合法吗?
假设我去编译一些编写不佳的C ++源代码,这些源代码会调用未定义的行为,因此(正如他们所说)“任何事情都可能发生”。 从C ++语言规范在“合格”编译器中认为可接受的角度来看,这种情况下的“任何情况”是否包括编译器崩溃(或窃取我的密码,或者在编译时出现异常或错误),或者未定义行为的范围专门限于生成的可执行文件运行时会发生什么?

5
未定义的行为和顺序点已重新加载
将此主题视为以下主题的续集: 上一期文章 未定义行为和顺序点 让我们重新看一下这个有趣而令人费解的表达(斜体字词来自上面的主题* smile *): i += ++i; 我们说这会调用未定义的行为。我相信,当这样说,我们隐含假设型的i是内置的类型之一。 如果什么类型的i是用户定义类型?说它的类型是本文Index后面定义的类型(请参阅下文)。它仍然会调用未定义行为吗? 如果是,为什么?它不等于写作i.operator+=(i.operator++());,甚至在语法上更简单 i.add(i.inc());吗?或者,他们是否也调用未定义行为? 如果没有,为什么不呢?毕竟,对象在连续的序列点之间i被修改了两次。请回想一下经验法则:表达式只能在连续的“序列点”之间修改对象的值一次。如果 i += ++i是表达式,则它必须调用undefined-behavior。如果是,则它的等效项i.operator+=(i.operator++());也 i.add(i.inc());必须调用undefined-behavior,似乎是不正确的!(据我了解) 或者,i += ++i不是一开始的表达方式吗?如果是这样,那么它是什么,expression的定义是什么? 如果它是一个表达式,并且其行为也得到了很好的定义,则意味着与该表达式关联的序列点数在某种程度上取决于该表达式所涉及的操作数的类型。我是否正确(甚至部分正确)? 顺便说一下,这个表情怎么样? //Consider two cases: //1. If a is an array of a built-in type //2. If a is user-defined type which overloads the subscript operator! a[++i] = i; …

3
在C ++中,有符号整数溢出仍然是未定义的行为吗?
众所周知,有符号整数溢出是未定义的行为。但是C ++ 11cstdint文档中有一些有趣的东西: 有符号整数类型,其宽度分别精确地为8、16、32和64位,没有填充位,并且对负值使用2的补码(仅在实现直接支持该类型时提供) 见链接 这里是我的问题:由于标准明确地说,对int8_t,int16_t,int32_t和int64_t负数是2的补,还是溢出这些类型的未定义的行为吗? 编辑我检查了C ++ 11和C11标准,这是我发现的内容: C ++ 11,第18.4.1节: 标头定义了与C标准中的7.20相同的所有函数,类型和宏。 C11,第7.20.1.1节: typedef名称intN_t指定宽度为N,无填充位和二进制补码表示形式的带符号整数类型。因此,int8_t表示具有正好8位宽度的这种有符号整数类型。

4
程序在在线IDE上表现异常
我遇到了以下C ++程序(源代码): #include <iostream> int main() { for (int i = 0; i < 300; i++) std::cout << i << " " << i * 12345678 << std::endl; } 它看起来像一个简单的程序,并在我的本地计算机上提供正确的输出,例如: 0 0 1 12345678 2 24691356 ... 297 -628300930 298 -615955252 299 -603609574 但是,在诸如codechef之类的在线IDE上,它提供以下输出: 0 0 1 12345678 2 24691356 …

7
(为什么)使用未初始化变量的未定义行为?
如果我有: unsigned int x; x -= x; 很显然,在此表达式之后x 应该为零,但是我所看到的所有地方都说该代码的行为是不确定的,而不仅仅是x(直到减法之前)的值。 两个问题: 此代码的行为确实未定义吗? (例如,代码是否可能在兼容的系统上崩溃?) 如果是这样,为什么C明确表示该行为x为零,为什么还说行为未定义? 即,通过在此不定义行为有什么好处? 显然,编译器可以在变量内部简单地使用它认为“方便”的任何垃圾值,并且可以按预期工作……该方法有什么问题?

12
在C / C ++中检测签名溢出
乍一看,这个问题似乎与“如何检测整数溢出”重复出现。,但实际上有很大的不同。 我发现,虽然检测无符号整数溢出非常简单,但是在C / C ++中检测带符号溢出实际上比大多数人想象的要困难。 最明显但最幼稚的方式是: int add(int lhs, int rhs) { int sum = lhs + rhs; if ((lhs >= 0 && sum < rhs) || (lhs < 0 && sum > rhs)) { /* an overflow has occurred */ abort(); } return sum; } 这样做的问题是根据C标准,有符号整数溢出是未定义的行为。 换句话说,根据标准,甚至在导致签名溢出时,程序就如同取消引用空指针一样无效。因此,您不能导致未定义的行为,然后尝试在事后检测溢出,如上述后置条件检查示例中所示。 即使上面的检查可能在许多编译器上都有效,但您不能指望它。实际上,由于C标准说未定义有符号整数溢出,因此某些编译器(如GCC)会在设置优化标志时优化上述检查,因为编译器认为有符号溢出是不可能的。这完全中断了检查溢出的尝试。 因此,另一种检查溢出的可能方法是: …

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.