相关疑难解决方法(0)

当左侧操作数具有负值时,为什么左移操作会调用未定义的行为?

在C中,当左侧操作数具有负值时,左移位操作会调用未定义的行为.

ISO C99相关引用(6.5.7/4)

E1 << E2的结果是E1左移E2位位置; 腾出的位用零填充.如果E1具有无符号类型,则结果的值为E1×2 E2,比结果类型中可表示的最大值减少一个模数.如果E1具有带符号类型和非负值,并且E1×2 E2可在结果类型中表示,那么这就是结果值; 否则,行为未定.

但在C++中,行为定义明确.

ISO C++ - 03(5.8/2)

E1 << E2的值是E1(解释为位模式)左移E2位位置; 空位是零填充的.如果E1具有无符号类型,则结果的值为E1乘以上升到功率E2的数量2,如果E1的类型为无符号长,则减少模ULONG_MAX + 1,否则为UINT_MAX + 1.[注意:标题中定义了常量ULONG_MAX和UINT_MAX).]

这意味着

int a = -1, b=2, c;
c= a << b ;
Run Code Online (Sandbox Code Playgroud)

在C中调用未定义的行为,但行为在C++中定义良好.

是什么迫使ISO C++委员会考虑与C中的行为相对应的行为?

另一方面,implementation defined当左操作数为负时,行为是按位右移操作,对吗?

我的问题是为什么左移操作在C中调用未定义的行为,为什么右移操作符只调用实现定义的行为?

PS:请不要给出答案,例如"这是未定义的行为,因为标准是这样说的".:P

c c++ bit-shift undefined-behavior language-lawyer

42
推荐指数
3
解决办法
2万
查看次数

左移(<<)是C++ 11中的负整数未定义行为吗?

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++ language-lawyer c++11

13
推荐指数
2
解决办法
4210
查看次数

C99中"算术运算"的定义是什么?

在C99中,术语算术运算出现了16次,但我没有看到它的定义.

术语算术运算符仅在文本中出现两次(同样没有定义)但它确实出现在索引中:

算术运算符

添加剂,6.5.6,
G.5.2按位,6.5.10,6.5.11,6.5.12
递增和递减
,6.5.2.4,6.5.3.1乘法6.5.5,G.5.1
移位,6.5.7
一元,6.5. 3.3

然后我们将+ - | &(二进制)++ -- *(二进制)/ % << >> ~作为算术运算符,如果索引被认为是规范的!

也许我们应该将算术运算识别为算术运算符的使用.但F9.4.5表示该sqrt()功能也是算术运算,详情请参考IEC 60559(又名IEEE754).因此,必须有算术运算,而不仅仅是算术运算符的使用.

c c99 language-lawyer

13
推荐指数
1
解决办法
299
查看次数

((float)rand()/(float)的含义((1 << 31) - 1))

我正在尝试理解一个包含.h文件的C程序

#define random                  ((float) rand() / (float)((1 << 31) - 1))
Run Code Online (Sandbox Code Playgroud)

C程序还包括<math.h>.

我的猜测是,这只是在区间[0,1]上从均匀分布产生一个随机数; 它是否正确?

c random

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

标签 统计

c ×3

language-lawyer ×3

c++ ×2

bit-shift ×1

c++11 ×1

c99 ×1

random ×1

undefined-behavior ×1