相关疑难解决方法(0)

在常量表达式中除以零

如果我在常量表达式中除以零,我的玩具编译器会崩溃:

int x = 1 / 0;
Run Code Online (Sandbox Code Playgroud)

C和/或C++标准是否允许这种行为?

c c++ compile-time-constant divide-by-zero constant-expression

43
推荐指数
3
解决办法
4102
查看次数

C在编译和执行程序之间有区别吗?

如果对表达式的求值导致C中的未定义行为,并且在执行程序时总是计算表达式(例如,如果它出现在开头main),那么如果实现在编译时拒绝它,它是否符合要求?在编译/翻译程序和执行程序之间,C有区别吗?

我知道有C的口译员.他们如何按照C标准处理这种差异?

示例(读取未初始化的本地)

int main() {
  int i;
  return i;
}
Run Code Online (Sandbox Code Playgroud)

在运行它时,在执行的任何阶段(甚至在main调用之前),程序都可以做一些有趣的事情.但是,当我们甚至没有试图运行它时,还会发生一些有趣的事吗?它会在编译器本身导致缓冲区溢出吗?

c language-lawyer

36
推荐指数
3
解决办法
2043
查看次数

无效指针再次变为有效

int *p;
{
    int x = 0;
    p = &x;
}
// p is no longer valid
{
    int x = 0;
    if (&x == p) {
        *p = 2;  // Is this valid?
    }
}
Run Code Online (Sandbox Code Playgroud)

在指向它的东西被释放后访问指针是未定义的行为,但是如果稍后的分配发生在同一区域会发生什么,并且您明确地将旧指针与指向新事物的指针进行比较?难道也无妨,如果我投&x,并puintptr_t比较之前?

(我知道不能保证这两个x变量占据相同的位置.我没有理由这样做,但我可以想象一个算法,你可以使用一组绝对有效的指针来交叉一组指针指针,删除过程中的无效指针.如果先前失效的指针等于已知的好指针,我很好奇会发生什么.)

c undefined-behavior

26
推荐指数
2
解决办法
1320
查看次数

是否定义了在无法到达的路径上具有未定义行为的程序的行为?

考虑

void swap(int* a, int* b)
{
    if (a != b){
        *a = *a ^ *b;
        *b = *a ^ *b;
        *a = *a ^ *b;
    }   
}

int main()
{
    int a = 0;
    int b = 1;
    swap(&a, &b); // after this b is 0 and a is 1
    return a > b ? 0 : a / b;
}
Run Code Online (Sandbox Code Playgroud)

swap 试图欺骗编译器不优化程序.

是否定义了此程序的行为?a / b是永远无法达到的,但如果是,那么你会得到除零.

c undefined-behavior language-lawyer

24
推荐指数
2
解决办法
1798
查看次数

具有从未实际执行的未定义行为的表达式是否会导致程序错误?

在关于未定义行为(UB)的许多讨论中,已经提出了这样的观点:在程序中存在任何具有UB的任何构造的程序都要求一致的实现做任何事情(包括什么都没有).我的问题是,即使在UB与代码执行相关联的情况下,是否应该采取这种方式,而标准中规定的行为(否则)规定不应执行相关代码(这可能是对于程序的特定输入;它可能在编译时不可判定).

更加非正式地说,UB的气味是否要求一致的实现来决定整个程序发臭,并且拒绝正确执行甚至行为完全明确定义的程序部分.一个示例程序将是

#include <iostream>

int main()
{
    int n = 0;
    if (false)
      n=n++;   // Undefined behaviour if it gets executed, which it doesn't
    std::cout << "Hi there.\n";
}
Run Code Online (Sandbox Code Playgroud)

为清楚起见,我假设程序格式正确(因此特别是UB与预处理无关).事实上,我愿意将UB限制为与"评估"相关联,而"评估"显然不是编译时实体.我认为,与给出的例子相关的定义(重点是我的):

之前排序的是由单个线程(1.10)执行评估之间的不对称,传递,成对关系,这导致这些评估之间的部分顺序

在运算符的结果的值计算之前,对运算符的操作数的值计算进行排序.如果对标量对象的副作用相对于...或使用相同标量对象的值进行值计算未被排序,则行为未定义.

隐含地清楚的是,最后一句中的主语"副作用"和"价值计算"是"评价"的实例,因为这就是定义"之前排序"的关系.

我认为在上述程序中,标准规定不进行评价,以满足最后一句中的条件(相对于彼此和所描述的类型),并且该程序不具有UB; 这不是错误的.

换句话说,我确信我的标题问题的答案是否定的.但是,我会很感激其他人对此事的(动机)意见.

对于那些主张肯定答案的人来说,可能还有一个问题是,当编译错误的程序时,会强制重新格式化硬盘吗?

本网站上的一些相关指针:

c++ undefined-behavior language-lawyer

19
推荐指数
3
解决办法
1117
查看次数

由 if (false) 保护的数据竞争...标准是怎么说的?

考虑以下情况

// Global
int x = 0; // not atomic

// Thread 1
x = 1;

// Thread 2
if (false)
    x = 2;
Run Code Online (Sandbox Code Playgroud)

根据标准,这是否构成数据竞争?[intro.races] 说:

如果两个表达式求值之一修改内存位置 (4.4),而另一个表达式求值读取或修改同一内存位置,则两个表达式求值会发生冲突。

如果程序的执行包含两个潜在并发冲突的操作,并且至少其中一个操作不是原子操作,并且两者都发生在另一个操作之前,则该程序的执行将包含数据争用,除了下面描述的信号处理程序的特殊情况之外。任何此类数据竞争都会导致未定义的行为。

从语言律师的角度来看是否安全,因为程序永远不能执行“表达式求值” x = 2;

从技术角度来看,如果某个奇怪、愚蠢的编译器决定对该写入执行推测执行,并在检查实际情况后将其回滚,该怎么办?

激发这个问题的原因是(至少在标准 11 中),允许以下程序的结果完全取决于重新排序/推测执行:

// Thread 1:
r1 = y.load(std::memory_order_relaxed);
if (r1 == 42) x.store(r1, std::memory_order_relaxed);
// Thread 2:
r2 = x.load(std::memory_order_relaxed);
if (r2 == 42) y.store(42, std::memory_order_relaxed);
// This is allowed to result in r1==r2==42 in c++11
Run Code Online (Sandbox Code Playgroud)

(比较https://en.cppreference.com/w/cpp/atomic/memory_order

c++ concurrency memory-model language-lawyer

18
推荐指数
2
解决办法
1275
查看次数

声明中的"未定义的行为"?

他们说,当有UB时,程序可以做任何想做的事情.

但如果我在一个声明中有UB,例如

signed char a = 0x40;
a <<= 2;
Run Code Online (Sandbox Code Playgroud)

或者甚至是一个未使用的(!)零大小的可变长度数组:

int l = 0;
char data[l];
Run Code Online (Sandbox Code Playgroud)

这是否可以忍受,因为只有结果是未定义的,或者这是"坏"吗?

我特别感兴趣的是这样的情况:

signed char a = 0x40;
a <<= 2;
switch (state) {
    case X: return
    case Y: do something with a; break;
    case Z: do something else with a; break;
}
Run Code Online (Sandbox Code Playgroud)

假设情况X涵盖了a未定义值的情况,而其他情况则使用了这种情况.如果我被允许按照我想要的方式计算并稍后进行区分,它会简化事情.

另一种情况是我前几天谈到的那个:

void send_stuff()
{
    char data[4 * !!flag1 + 2 * !!flag2];
    uint8_t cursor = 0;
    if (flag1) {
        // fill 4 bytes of data into …
Run Code Online (Sandbox Code Playgroud)

c undefined-behavior

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

为什么使用指向一个成员变量的指针调用函数会抑制其他成员变量的优化?

考虑以下程序:

struct X {
    bool b;
    int y;
};

void f(int*);

bool test(X x) {
    if (!x.b) {
        return false;
    }
    f(&x.y);
    return x.b;
}
Run Code Online (Sandbox Code Playgroud)

看来声明

    return x.b;
Run Code Online (Sandbox Code Playgroud)

没有得到优化return true; 所以我的结论是,编译器必须假设可以通过这样做进行f(int*)修改:x.b

void f(int* p) {
    bool* q = reinterpret_cast<bool*>(p - 1);
    *q = false;
}
Run Code Online (Sandbox Code Playgroud)

f这是真正有效的 C++实现吗?或者换句话说,当指向成员的指针传递给不透明函数时,编译器是否必须始终假设整个对象可能会发生变化?

带有 clang-x86 trunk (-O1) 的编译器输出是这样的:

test(X):                              # @test(X)
        push    rax
        mov     qword ptr [rsp], rdi
        test    dil, dil
        je      .LBB0_1
        lea     rdi, [rsp + 4]
        call    f(int*)@PLT
        cmp …
Run Code Online (Sandbox Code Playgroud)

c++ optimization language-lawyer

6
推荐指数
2
解决办法
134
查看次数

在C中使用双下划线

我正在读书C programming a modern approach.我发现了一个问题:

为什么标识符包含多个相邻的下划线并不是一个好主意(例如,在current__balance中)?

任何人都可以向我解释为什么会如此?

c

3
推荐指数
1
解决办法
1853
查看次数