C++ 无符号整数换行,不同的行为

C++ 无符号整数换行,不同的行为,c++,c,C++,C,以下是C语言的代码: #include <stdio.h> int main() { printf("Int width = %lu\n", sizeof(unsigned int)); // Gives 32 bits on my computer unsigned int n = 32; unsigned int y = ((unsigned int)1 << n) - 1; // This is line 8

以下是C语言的代码:

#include <stdio.h>

int main()
{
    printf("Int width = %lu\n", sizeof(unsigned int)); // Gives 32 bits on my computer

    unsigned int n = 32;
    unsigned int y = ((unsigned int)1 << n) - 1;  // This is line 8
    printf("%u\n", y);
    
    unsigned int x = ((unsigned int)1 << 32) - 1; // This is line 11
    printf("%u", x);
    
    return 0;
}
第11行的警告如以下链接所述:和

左移位操作[…]如果右操作数的值为负数或大于或等于提升后的左操作数的宽度,则行为未定义

8号线没有任何警告,但我预期的警告与11号线相同。而且,结果完全不同!我错过了什么

这种行为与C++类似:

#include <iostream>
using namespace std;
int main()
{
    cout << "Int width = " << sizeof(uint64_t) << "\n"; // Gives 64 bits on my computer

    int n = 64;
    uint64_t y = ((uint64_t)1 << n) - 1; // This is line 8
    cout << "y = " << y;
    
    uint64_t x = ((uint64_t)1 << 64) - 1; // This is line 11
    cout << "\nx = " << x;

    return 0;
}
我使用了C代码和编译器的编译器。 以下是代码的链接:和。

可能是因为n是一个变量,编译器似乎没有验证它,因为它不知道它的值,如果将它转换为常量,即const int n=64;,它不会发出警告;,警告已经发出

至于结果,未定义的行为就是它,出于好奇,您可以分析一个特定的情况,并尝试找出编译器做了什么,但结果无法推理,因为没有正确的结果


即使警告是可选的,gcc也可以在使用常量或常量文字时向您发出警告,但它不必发出警告。

对于第8行,编译器必须在unsigned int1中证明这一点 8号线没有任何警告,但我预期的警告与11号线相同

C标准不需要编译器来诊断过多的移位量。通常,除了“约束”子句中明确列出的错误外,它不需要C实现来诊断错误

您使用的编译器使用整型常量表达式32诊断错误,因为这很简单。它不会用变量n诊断错误,因为这需要更多的工作,而且编译器作者还没有实现它

而且,结果完全不同


对于整型常量表达式,编译器在编译期间使用内置的任何软件计算移位。这显然为无符号int 1产生了零未定义的行为UB表示未定义的行为。事实上,任何事情都可能发生。编译器不需要告诉您UB,但允许告诉您UB

如果右操作数的值为负或大于或等于提升后的左操作数的宽度,则行为未定义

因此,在云存储文件上安装病毒并通过电子邮件将浏览器历史记录发送到联系人列表时,最大未签名-1或零,或格式化SSD都是允许编译器转换32位整数的32位移位的事情

作为一个执行质量问题,最后一个问题很少出现


<编译器>优化1C和C++是不同的。选择一个语言来解决问题。未定义的行为是未定义的。在C const中与C++没有完全相同,如果使用一个常数,定义n 32,则得到警告。我只是觉得编译器会更愿意发出警告,因为如果它至少标记为const,它的值就不会改变。Undefined Behavior UB表示Undefined Behavior。-那是无限的误导!“未定义的行为”仅表示C标准没有强加任何要求。它并没有断言任何事情都可能发生。它不会也不能解除法律、物理、硬件规格、材料约束、数学或逻辑强加的要求。@EricPostChil你是否声称未定义的行为不能穿越时间?因为我可以给你举个例子。如果程序的行为未被C++标准定义,则程序在遇到触发代码之前的行为也未被C++标准定义。所以UB代码的效果可以使时间倒转,使代码在运行之前发生变化。当然,它可能违反硬件规范;经典的UB之一是运行硬件不支持的ASM指令,这会导致CPU执行非常随机的操作。@Yakk AdamNevraumont:不,我不是这么说的。“任何事情都可能发生”的说法是错误的。C标准说行为是“未定义的”,这一事实仅意味着C标准没有对行为施加任何要求。它不会消除行为上的其他约束。行为上的其他约束继续存在,并阻止某些事情发生。这就是为什么“任何事情都可能发生”的说法是错误的……这会产生实际的后果,从实现定义的扩展到继续定义“任何事情都可能发生”都是错误的如果编译器文档指定它支持一个适用的扩展来填充C标准中未定义的行为,以提供诊断错误的有用线索,那么当编译器设计的结果说明程序如何错误地保护人的生命时,“任何事情都可能发生”就不是真的 当法律要求产品安全时,“任何事情都可能发生”不是真的。告诉人们“任何事情都可能发生”会误导他们。
#include <iostream>
using namespace std;
int main()
{
    cout << "Int width = " << sizeof(uint64_t) << "\n"; // Gives 64 bits on my computer

    int n = 64;
    uint64_t y = ((uint64_t)1 << n) - 1; // This is line 8
    cout << "y = " << y;
    
    uint64_t x = ((uint64_t)1 << 64) - 1; // This is line 11
    cout << "\nx = " << x;

    return 0;
}
main.cpp:11:34: warning: left shift count >= width of type [-Wshift-count-overflow]                                                            
Int width = 8                                                                                                                                  
y = 0                                                                                                                                          
x = 18 446 744 073 709 551 615 (= 2^64-1)