我正在研究核心常量表达式*中允许的内容,这在C++标准草案的5.19 常量表达式第2段中有所描述:
条件表达式是核心常量表达式,除非它涉及以下之一作为潜在评估的子表达式(3.2),但是未评估的逻辑AND(5.14),逻辑OR(5.15)和条件(5.16)操作的子表达式不考虑[注意:重载的运算符调用函数.-end note]:
并列出随后的子弹中的排除项并包括(强调我的):
- 具有未定义行为的操作 [注意:包括,例如,有符号整数溢出(第5条),某些指针算术(5.7),除零(5.6)或某些移位操作(5.8) - 结束注释];
嗯?为什么常量表达式需要此子句来涵盖未定义的行为?常量表达式是否有一些特殊的东西需要未定义的行为才能在排除中进行特殊划分?
拥有这个条款是否给了我们没有它的任何优势或工具?
作为参考,这看起来像广义常量表达式提案的最新修订版.
我编写了以下程序来输出一个整数的二进制等价物(我检查了我的系统上的int是4个字节)它是4个字节.但输出并不合适.代码是:
#include<iostream>
#include<iomanip>
using namespace std;
void printBinary(int k){
for(int i = 0; i <= 31; i++){
if(k & ((1 << 31) >> i))
cout << "1";
else
cout << "0";
}
}
int main(){
printBinary(12);
}
Run Code Online (Sandbox Code Playgroud)
我哪里弄错了?
int在C++ 11中左移一个负的未定义行为?
这里的相关标准段落来自5.8:
2/E1 << E2的值是E1左移E2位的位置; 空位是零填充的.如果E1具有无符号类型,则结果的值为E1×2E2,比结果类型中可表示的最大值减少一个模数.否则,如果E1具有有符号类型和非负值,并且在结果类型中可以表示E1×2E2,那么这就是结果值; 否则,行为未定义.
令我困惑的部分是:
否则,如果E1具有有符号类型和非负值,并且在结果类型中可以表示E1×2E2,那么这就是结果值; 否则,行为未定义.
这应该被解释为左移任何负数是UB吗?或者它只是意味着如果你的LS为负数且结果不适合结果类型,那么它是UB?
而且,前面的条款说:
1 /移位运算符<<和>>组从左到右.shift-expression:additive-expression shift-expression << additive-expression shift-expression >> additive-expression
操作数应为整数或无范围的枚举类型,并执行整体促销.
结果的类型是提升的左操作数的类型.如果右操作数为负数,或者大于或等于提升左操作数的位长度,则行为未定义.
这使得明确表示对其中一个操作数使用负数是UB.如果UB对另一个操作数使用负数,我希望在这里也要明确.
所以,底线是:
-1 << 1
Run Code Online (Sandbox Code Playgroud)
未定义的行为?
@Angew 提供了对Standardese的psudocode解释,它简洁地表达了一种可能(可能)有效的解释.其他人质疑这个问题是否真的与"行为未定义"的语言的适用性相比,而我们(StackOverflow)使用了"未定义行为"这一短语.这个编辑是为了提供一些我想要问的更多说明.
@Angew对Standardese的解释是:
if (typeof(E1) == unsigned integral)
value = E1 * 2^E2 % blah blah;
else if (typeof(E1) == signed integral && E1 >= 0 && representable(E1 * 2^E2))
value = E1 * 2^E2;
else
value = undefined;
Run Code Online (Sandbox Code Playgroud)
这个问题真正归结为这个 - …
我理解为什么C++将INT_MIN定义为(-2147483647-1),但为什么它们不使用1 << 31?这样可以防止溢出并且易于理解.
#define SCALE (1 << 31)
#define fix_Q31_80(x) ( (int) ( (float)(x)*(float)0x80000000 ) )
#define fix_Q31_SC(x) ( (int) ( (float)(x)*(float)SCALE ) )
int main()
{
int fix_80 = fix_Q31_80(0.5f);
int fix_sc = fix_Q31_SC(0.5f);
}
Run Code Online (Sandbox Code Playgroud)
为什么价值观fix_80和fix_sc不同?
fix_80 == Hex:0x40000000
fix_sc == Hex:0xc0000000
Run Code Online (Sandbox Code Playgroud) 当我这样做(0x7fffffff | 0x8000000)时,我得到0xffffffffffffffff而不是预期的0xffffffff.我错过了什么?
一些示例代码和输出来说明我的问题.
码:
#include <iostream>
using namespace std;
int main()
{
unsigned long long val = 0;
for (int i = 0; i < 64; i++) {
val |= 0x1 << i;
cout << i << ": " << std::hex << val << std::dec << endl;
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出:
0: 1 1: 3 2: 7 3: f 4: 1f 5: 3f 6: 7f 7: ff 8: 1ff 9: 3ff 10: 7ff 11: fff 12: 1fff 13: …
特定
int a = 1;(00000000000000000000000000000001),
我做的只是
a=(a<<31)>>31;
Run Code Online (Sandbox Code Playgroud)
我认为a应该仍然1在这个陈述之后(我认为没有改变).但事实证明是-1(11111111111111111111111111111111).谁知道为什么?