标签: unspecified-behavior

是否未指定标准库头是否包含任意标头?

有一个声明,C++标准库中的哪些标头保证包含另一个标头?:

C++标准库头可以以未指定的方式彼此包含,因此程序员通常不应该依赖于包括另一个的一个头.[...]

在实践中,情况往往如此.例如,<iostream>可能包括<string>,在其他情况下,您需要<string>明确包含.但是,我似乎无法在N4140中找到这种情况.我查了一下:

  • §2.9[lex.header]
  • §17.6.1.2[标题]
  • §17.6.2.2[using.headers]
  • §17.6.4.4[alt.headers]
  • §17.6.5.2[res.on.headers]

我能找到的最近的是来自[using.headers]:

2翻译单元可以包括任何顺序的图书馆标题(第2条).每个可以被包括不止一次,除了每次包含<cassert><assert.h>依赖于NDEBUG的词法当前定义的效果之外,没有任何效果与仅包括一次有效.178

但这似乎适用于C++程序,而不是标准库:

[using.overview]/1本节介绍C++程序如何访问C++标准库的工具.[...]

和[res.on.headers]一样:

1 C++标头可能包含其他C++标头.C++标头应提供其概要中出现的声明和定义.在其概要中显示的包含其他C++头的C++头应提供出现在那些其他头的概要中的声明和定义.

我认为关键是第一句话,但它没有明确说明它是未指明的行为.它是否在任何地方声明这是未指明的行为还是只是暗示?

c++ header-files language-lawyer unspecified-behavior

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

为什么要分两步进行位移?

Linux 内核中,我找到了以下代码:

static inline loff_t pos_from_hilo(unsigned long high, unsigned long low)
{
#define HALF_LONG_BITS (BITS_PER_LONG / 2)
    return (((loff_t)high << HALF_LONG_BITS) << HALF_LONG_BITS) | low;
}
Run Code Online (Sandbox Code Playgroud)

该代码用于将系统调用参数组合成一个更宽的变量,因此例如在 ia32 上,偏移量pwritev在两个 32 位寄存器中指定。

在 x64 上,loff_t并且unsigned long都是 64 位宽。在这种情况下,high变量将被忽略并仅low被使用。在 ia32 上,loff_t是 64 位宽和unsigned long32 位宽。在这种情况下,两个参数highlow组合在一起。

我想知道为什么代码移位两次而不是一次。在提交消息和 LWN 文章中有更多关于此代码的信息系统调用和 64 位体系结构,但没有解释双位移位。

c linux bit-manipulation unspecified-behavior

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

指针比较是否在C++中未定义或未指定的行为?

Stroustrup的C++编程语言第3版说,

仅当两个指针指向同一数组的元素时才定义指针的减法(尽管该语言没有确保情况的快速方法).从另一个指针中减去一个指针时,结果是两个指针之间的数组元素数(一个整数).可以向指针添加整数或从指针中减去整数; 在这两种情况下,结果都是指针值. 如果该值未指向与原始指针相同的数组或超出原始指针的元素,则使用该值的结果是未定义的.

例如:

void f ()
{
    int v1 [10];
    int v2 [10];
    int i1 = &v1[5] - &v1[3];   // i1 = 2
    int i2 = &v1[5] - &v2[3];   // result undefined
}
Run Code Online (Sandbox Code Playgroud)

我正在阅读维基百科上未指明的行为.它说

在C和C++中,如果指针指向同一对象的成员或同一数组的元素,则仅严格定义指向对象的指针.

例:

int main(void)
{
  int a = 0;
  int b = 0;
  return &a < &b; /* unspecified behavior in C++, undefined in C */
}
Run Code Online (Sandbox Code Playgroud)

所以,我很困惑.哪一个是正确的?维基百科或Stroustrup的书?C++标准对此有何看法?

纠正我如果我误解了什么.

c++ pointers undefined-behavior unspecified-behavior

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

此代码是否会产生未定义的行为,或者它只是未指定的行为?

可以说我们有两个编译单元如下:

// a.cpp
extern int value2;
int value1 = value2 + 10;

// b.cpp
extern int value1;
int value2 = value1 + 10;
Run Code Online (Sandbox Code Playgroud)

当我在VC2010上尝试它时,它首先初始化value1value2归零.不能全是value1value2动态初始化,并默认初始化不会对他们适用?

谢谢,

c++ primitive-types undefined-behavior static-order-fiasco unspecified-behavior

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

是否可以在constexpr上下文中使用指针导致未指定(未定义!)的行为?

根据cppreference(强调我的):

核心常量表达式是任何子表达式中没有以下任何一个的表达式
(...)

  1. 一种表达式,其评估会导致任何形式的核心语言未定义行为(包括有符号整数溢出,除零,数组边界外的指针运算等).是否未指定检测到标准库未定义行为.

另一方面,指针上有几个表达式,结果不是未定义但未指定(参见[expr.rel]/3),例如:

struct A {
    int v;
};

struct B {
    int v;
};

struct C: A, B {} c;

int main() {
    constexpr bool result = &c.A::v < &c.B::v;
    (void)result;
}
Run Code Online (Sandbox Code Playgroud)

代码编译没有gcc的问题,但没有在clang中编写,其中说明无疑是真的:

不同基类的子对象地址的比较尚未明确

但是(根据我的理解),根据cppreference它不应该阻止编译器编译代码.

哪个编译器就在这里 - gcc还是clang?我是否过度解释了cppreference?

c++ language-lawyer unspecified-behavior constexpr c++11

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

如何在函数参数初始化中捕获未定义的行为

以下代码在clang ++中有效,但在g ++中崩溃了

#include<vector>
#include<iostream>

template<class Iterator>
double abs_sum(double current_sum, Iterator it, Iterator it_end){
    if (it == it_end)
        return current_sum;
    return abs_sum(current_sum+std::abs(*it),++it,it_end);
}


int main(int argc, char** argv){
    std::vector<double> values {1.0, 2.0,-5};

    std::cout << abs_sum(0.0,values.begin(),values.end()) << std::endl;;
}
Run Code Online (Sandbox Code Playgroud)

罪魁祸首证明是这条线:

return abs_sum(current_sum+std::abs(*it),++it,it_end);
Run Code Online (Sandbox Code Playgroud)

在clang中,*it在之前进行评估++it,在g ++中它是相反的,导致迭代器在被解除引用之前被增加.事实证明,评估函数参数的顺序是实现定义的.

我的问题是:我如何捕获此类错误?理想情况下,当我意外地依赖于具体实施细节时,我想要出错或至少发出警告.

即使用-Wall,clang和gcc都不会发出任何警告.

c++ undefined-behavior unspecified-behavior

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

空基类是否应该影响派生类的布局?

C++标准(引自草案n3242)说明以下关于子对象[intro.object]:

除非对象是零字段或零大小的基类子对象,否则该对象的地址是它占用的第一个字节的地址.两个不同的对象既不是位字段也不是零大小的基类子对象应具有不同的地址.

现在,给出以下代码段:

struct empty { };
struct member: empty { };
struct derived: empty { member m; };

int main(void)
{
    printf("%d", sizeof(derived));
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

gcc我相信打印出来2,而Visual C++ 2010打印出来1.我怀疑gcc正在采用标准来表示如果它们代表不同的对象,则不能对类型的存储进行别名.我打赌MSVC正在采用标准来表示如果一个子对象是零大小,你可以做任何你想做的事情.

这是不明确的行为吗?

c++ standards unspecified-behavior

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

给定代码中的未定义行为?

如果在呼叫之前将p的值初始化为5,则f(p,p)的返回值是多少?请注意,第一个参数通过引用传递,而第二个参数按值传递.

int f (int &x, int c) {
       c = c - 1;
       if (c==0) return 1;
       x = x + 1;
       return f(x,c) * x;
}
Run Code Online (Sandbox Code Playgroud)

选项包括:

  1. 3024
  2. 6561
  3. 55440
  4. 161051

我试着解释一下:


在这段代码中,将有四个带参数(6,4),(7,3),(8,2)和(9,1)的递归调用.最后一次调用返回1.但是由于通过引用传递,所有先前函数中的x现在是9.因此,f(p,p)返回的值将是9*9*9*9*1 = 6561.


这个问题来自竞争性考试GATE,(见Q.no.-42).答案密钥由GATE"Marks to all"给出(表示没有选项正确.)key set-C,Q.no.-42.在某处解释为:

在GATE 2013中,所有人都给出了标记,因为C/C++中的相同代码会产生未定义的行为.这是因为*它不是C/C++中的序列点.必须替换正确的代码

return f(x,c) * x;
Run Code Online (Sandbox Code Playgroud)

 res = f(x,c);
 return res * x;
Run Code Online (Sandbox Code Playgroud)

但是给定的代码工作正常.GATE的关键是错的吗?或者问题确实是错误的?

c c++ undefined-behavior unspecified-behavior c++11

5
推荐指数
2
解决办法
344
查看次数

在C中调用函数时的序列点和未定义/未指定的行为

我试图确定我对C中序列点的理解 - 只是想检查一下.目前,我认为(1)是未定义的,而(2)仅仅是未指定的,因为在(2)中,在评估参数gh(因此我们不在i序列点之间修改两次)之后存在序列点,但是参数的评估顺序f仍未指定.我的理解是否正确?

#include <stdio.h>

int g(int i) {
    return i;
}

int h(int i) {
    return i;
}

void f(int x, int y) {
    printf("%i", x + y);
}

int main() {
    int i = 23;
    f(++i, ++i); // (1)
    f(g(++i), h(++i)); // (2)
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

编辑:

这里的关键点似乎是编译器是否可以自由地在任何一个g或者h被调用之前执行增量- 我从下面的答案中理解它是,尽管我很欣赏确认情况就是这样.

c undefined-behavior sequence-points language-lawyer unspecified-behavior

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

索引一个新的map元素并且有一些东西读取它分配给它未定义的行为,或者只是未指定?

在回答了这个问题之后,对于有问题的代码是否是未定义的行为进行了长时间的讨论.这是代码:

std::map<string, size_t> word_count;
word_count["a"] = word_count.count("a") == 0 ? 1 : 2;
Run Code Online (Sandbox Code Playgroud)

首先,至少没有具体说明这一点已经确定.结果根据首先评估分配的哪一侧而不同.在我的回答中,我跟踪了四个结果案例中的每一个,其中包括首先评估哪一方的因素以及该元素之前是否存在.

还有一个简短的表格:

(x = 0) = (x == 0) ? 1 : 2; //started as
(x = 0) = (y == "a") ? 1 : 2; //changed to
Run Code Online (Sandbox Code Playgroud)

我声称它更像是这样的:

(x = 0, x) = (x == 0) ? 1 : 2; //comma sequences x, like [] should
Run Code Online (Sandbox Code Playgroud)

最后,我找到了一个似乎对我有用的例子:

i = (++i,i++,i); //well-defined per SO:Undefined Behaviour and Sequence Points
Run Code Online (Sandbox Code Playgroud)

回到原文,我把它分解成相关的函数调用,以便更容易理解:

operator=(word_count.operator[]("a"), word_count.count("a") == 0 …
Run Code Online (Sandbox Code Playgroud)

c++ operator-precedence undefined-behavior sequence-points unspecified-behavior

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