Questions tagged «undefined-behavior»

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


3
如果a未初始化,a ^ a或aa是未定义的行为吗?
考虑以下程序: #include <stdio.h> int main(void) { unsigned int a; printf("%u %u\n", a^a, a-a); return 0; } 它是不确定的行为吗? 表面上a是一个未初始化的变量。因此,这指向未定义的行为。但是a^a和a-a等于0的所有值a,至少我认为是这种情况。是否有某种方法可以证明行为已被明确定义?

4
C ++编译错误?
我有以下代码: #include <iostream> #include <complex> using namespace std; int main() { complex<int> delta; complex<int> mc[4] = {0}; for(int di = 0; di < 4; di++, delta = mc[di]) { cout << di << endl; } return 0; } 我希望它输出“ 0、1、2、3”并停止,但输出的序列是“ 0、1、2、3、4、5,..”。 看起来比较di<4效果不佳,并且总是返回true。 如果我只是将其注释掉,delta=mc[di],我会像往常一样得到“ 0,1,2,3”。无辜的任务有什么问题? 我正在使用带有-O2选项的Ideone.com g ++ C ++ 14。

5
在C / C ++中进行无符号左移之前的掩盖是否过于偏执?
这个问题的动机是由我在C / C ++中实现加密算法(例如SHA-1),编写与平台无关的可移植代码以及彻底避免未定义的行为引起的。 假设标准的加密算法要求您实现此目的: b = (a << 31) & 0xFFFFFFFF 其中a和b是无符号的32位整数。注意,在结果中,我们丢弃了最低有效32位以上的任何位。 作为第一个幼稚的近似值,我们可以假设int在大多数平台上该宽度为32位,因此我们可以这样写: unsigned int a = (...); unsigned int b = a << 31; 我们知道该代码不会在任何地方都起作用,因为int在某些系统上为16位宽,在其他系统上为64位,甚至可能为36位。但是使用stdint.h,我们可以使用以下uint32_t类型来改进此代码: uint32_t a = (...); uint32_t b = a << 31; 这样我们就完成了,对吧?这就是我多年以来的想法。... 不完全的。假设在某个平台上,我们有: // stdint.h typedef unsigned short uint32_t; 在C / C ++中执行算术运算的规则是,如果类型(例如short)比窄int,则将其扩展到int所有值都适合的范围,unsigned int否则。 …

11
遇到C的常见未定义/未指定行为是什么?[关闭]
已关闭。这个问题需要更加集中。它当前不接受答案。 想改善这个问题吗?更新问题,使其仅通过编辑此帖子来关注一个问题。 7年前关闭。 改善这个问题 C语言中未指定行为的一个示例是对函数自变量的求值顺序。您可能不知道它可能是从左到右或从右到左。这将如何影响foo(c++, c)或foo(++c, c)获取评估。 还有哪些其他未说明的行为可能会使无意识的程序员感到惊讶?

10
C ++中的签名溢出和未定义的行为(UB)
我想知道以下代码的使用 int result = 0; int factor = 1; for (...) { result = ... factor *= 10; } return result; 如果循环是随着n时间反复进行的,则将factor其乘以10精确的n时间。但是,factor仅在相乘10了总n-1次数后才使用。如果我们假设factor除了在循环的最后一次迭代中永远不会溢出,而是可能在循环的最后一次迭代中溢出,那么这样的代码是否可以接受?在这种情况下,factor证明溢出后永远不会使用的值。 我正在就是否应接受此类代码进行辩论。可以将乘法放在if语句中,并且在可能溢出时,不对循环的最后一次迭代进行乘法。缺点是它会使代码混乱,并添加了一个不必要的分支,需要在所有先前的循环迭代中进行检查。我还可以减少循环迭代一次,并在循环之后复制一次循环主体,这又使代码复杂化。 有问题的实际代码在一个紧密的内部循环中使用,该循环在实时图形应用程序中消耗大量的总CPU时间。

3
递增指向0大小的动态数组的指针是否未定义?
AFAIK,尽管我们无法创建大小为0的静态内存数组,但是我们可以使用动态数组来做到这一点: int a[0]{}; // Compile-time error int* p = new int[0]; // Is well-defined 如我所读,p行为就像一个过去的元素。我可以打印p指向的地址。 if(p) cout << p << endl; 尽管我确定我们不能像使用迭代器(过去元素)那样取消引用该指针(过去元素),但是我不确定是否要增加该指针p?是否像迭代器一样具有未定义的行为(UB)? p++; // UB?

7
指针比较在C中如何工作?比较不指向同一数组的指针是否可以?
在K&R(C编程语言第二版)第5章中,我阅读了以下内容: 首先,可以在某些情况下比较指针。如果p和q指向同一个数组的成员,则关系一样==,!=,<,>=,等正常工作。 这似乎暗示着只能比较指向同一数组的指针。 但是当我尝试这段代码时 char t = 't'; char *pt = &t; char x = 'x'; char *px = &x; printf("%d\n", pt > px); 1 被打印到屏幕上。 首先,我以为我会得到未定义或某种类型或错误的信息,因为pt和px没有指向同一数组(至少在我看来)。 同样是pt > px因为两个指针都指向存储在堆栈中的变量,并且堆栈变小,所以的内存地址t大于x?的内存地址。这是为什么pt > px呢? 引入malloc时,我会更加困惑。同样,在K&R的8.7章中,内容如下: 但是,仍然有一个假设,即sbrk可以有意义地比较指向返回的不同块的指针。该标准不能保证这一点,该标准仅允许在数组内进行指针比较。因此,此版本malloc仅可在通用指针比较有意义的机器之间移植。 将指向堆上分配的空间的指针与指向堆栈变量的指针进行比较,我没有任何问题。 例如,以下代码可以很好地工作并1可以打印: char t = 't'; char *pt = &t; char *px = malloc(10); strcpy(px, pt); …

2
添加到std :: vector时类字段的行为异常
在以下情况下,我发现了一些非常奇怪的行为(在clang和GCC上)。我有一个向量,nodes有一个元素,一个class的实例Node。然后,我在上调用一个函数nodes[0],Node以向向量添加新的函数。添加新节点后,将重置调用对象的字段!但是,一旦功能完成,它们似乎又恢复正常。 我相信这是一个最小的可复制示例: #include <iostream> #include <vector> using namespace std; struct Node; vector<Node> nodes; struct Node{ int X; void set(){ X = 3; cout << "Before, X = " << X << endl; nodes.push_back(Node()); cout << "After, X = " << X << endl; } }; int main() { nodes = …

4
使用未初始化的成员复制结构
复制一个未初始化其成员的结构是否有效? 我怀疑这是未定义的行为,但如果是这样,则会使任何未初始化的成员保留在结构中(即使从未直接使用这些成员)也很危险。所以我想知道标准中是否有允许它的东西。 例如,这有效吗? struct Data { int a, b; }; int main() { Data data; data.a = 5; Data data2 = data; }

3
C是否与C ++具有等效的std :: less?
我最近在回答一个关于p < q当p和q是指向不同对象/数组的指针时在C 中执行的未定义行为的问题。这让我想到:C ++ <在这种情况下具有相同(未定义)的行为,但是还提供了标准库模板std::less,该模板保证可以返回与<可以比较指针时相同的东西,并在不能比较时返回一些一致的顺序。 C是否提供具有类似功能的东西,从而可以安全地比较任意指针(相同类型)?我尝试浏览C11标准并没有发现任何东西,但是我在C中的经验比在C ++中小得多,因此我很容易错过一些东西。

1
为什么约束函数允许未定义的行为?
C ++中的常量表达式具有非常整洁的特性:它们的求值不能具有未定义的行为(7.7.4.7): 表达式e是核心常量表达式,除非按照抽象机([intro.execution])的规则对e求值,将求出以下值之一: ... 一种操作,其操作将具有本文档的[引言] [cpp]中指定的未定义的行为[注意:例如,包括有符号整数溢出([expr.prop]),某些指针算术([expr.add],除以零或某些移位操作-尾注]; 尝试将13!in 的值存储在constexpr int确实产生一个不错的编译错误: constexpr int f(int n) { int r = n--; for (; n > 1; --n) r *= n; return r; } int main() { constexpr int x = f(13); return x; } 输出: 9:19: error: constexpr variable 'x' must be initialized …

2
程序永远不会终止有效的C ++程序吗?
是否需要终止程序?换句话说,是一个在技术上永远无法运行的程序吗?请注意,这与空循环无关。谈论永远做“东西”(即可观察到的行为)的程序。 例如这样的事情: int main() { while (true) { try { get_input(); // calls IO process(); put_output(); // calls IO, has observable behavior // never break, exit, terminate, etc } catch(...) { // ignore all exceptions // don't (re)throw // never go out of loop } } } 这更多是一个学术问题,因为根据经验,所有理智的编译器都会为上述程序生成预期的代码(当然,假设没有其他UB来源)。是的,当然,有很多程序永远都不会终止(操作系统,嵌入式服务器)。但是有时标准是古怪的,因此是个问题。 切线:“算法”的许多(某些)定义要求算法必须终止,即,一系列永不终止的运算不被视为算法。 相切的。暂停问题指出,无法存在一种算法来确定任意程序是否针对输入完成。但是,对于该特定程序,由于没有导致退出main的分支,因此编译器可以轻松确定该程序永远不会结束。但是,这是无关紧要的,因为问题是语言律师。

3
具有非常量指针和相同地址的const参数的指针的函数调用
我想编写一个函数,该函数输入一个数据数组并使用指针输出另一个数据数组。 我想知道如果两者都指向同一地址会产生什么结果src,dst因为我知道编译器可以针对const进行优化。它是未定义的行为吗?(我同时标记了C和C ++,因为我不确定答案是否可能会有所不同,并且我想了解两者。) void f(const char *src, char *dst) { dst[2] = src[0]; dst[1] = src[1]; dst[0] = src[2]; } int main() { char s[] = "123"; f(s,s); printf("%s\n", s); return 0; } 除了上述问题,如果删除const原始代码中的,是否定义明确?

1
原始static_vector实现中可能的未定义行为
tl;博士:我认为我的static_vector具有未定义的行为,但我找不到它。 这个问题是在Microsoft Visual C ++ 17上实现的。我有一个简单而未完成的static_vector实现,即一个具有固定容量的矢量,可以堆栈分配。这是一个C ++ 17程序,使用std :: aligned_storage和std :: launder。我试图将其归结为以下我认为与该问题相关的部分: template <typename T, size_t NCapacity> class static_vector { public: typedef typename std::remove_cv<T>::type value_type; typedef size_t size_type; typedef T* pointer; typedef const T* const_pointer; typedef T& reference; typedef const T& const_reference; static_vector() noexcept : count() { } ~static_vector() { …

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.