struct Type {
    uint8_t var : 3;
};

int main()
{
    struct Type bar;
    bar.var = 1;
    uint8_t baz = bar.var << 5;
}

根据标准,左移位大于左操作数类型的宽度是未定义的行为:

6.5.7 Bitwise shift operators/3对每个操作数执行整数提升.结果的类型是升级的左操作数的类型.If the value of the right operand is negative or is greater than or equal to the width of the promoted left operand, the behavior is undefined.

但是位字段呢?这里不是至少有八个比特吗?

推荐答案

将引用左操作数的整数提升.以下为相关推介:

6.3.1.1.2[...]如果100可以表示原始类型的所有值(受位域的宽度限制),则将该值转换为100;[...]

升级后的左操作数为int.


关于转移,规范上说

6.5.7.3在每个操作数上执行整数提升.结果的类型是升级的左操作数的类型.如果右操作数的值为负数或大于或等于提升的左操作数的宽度,则行为未定义.

提升的左操作数的宽度--int的宽度--至少是16.5,远远小于16.

目前还没有不确定的行为.


说明书还在继续:

6.5.7.4 E1 << E2的结果是E1位左移E2位;空出的位用零填充.如果E1具有无符号类型,则结果的值是E1×2E2,模减1比结果类型中可表示的最大值多1.如果E1具有带符号的类型和非负值,并且在结果类型中可以表示E1×2E2,则这是结果值;否则,行为是未定义的.

我不清楚"E1式"是指晋升前的bar.var式,还是升职后的bar.var式.

  • 如果在升职之前,

    E1具有无符号类型.

  • 如果升职后,

    E1具有带符号的类型.但是,值bar.var都不会导致负提升值,并且值bar.var乘以25都不会超过int所能表示的值.

无论哪种方式,目前还没有不确定的行为.


最后,我们要完成作业(job)了.

6.5.16.1.2在simple assignment(=)中,右操作数的值被转换为赋值表达式的类型,并替换存储在由左操作数指定的对象中的值.

6.3.1.3.2否则,如果新类型是无符号的,则通过重复加减新类型可以表示的最大值1来换算该值,直到该值处于新类型的范围内.60)

那里也没有不确定的行为.

C++相关问答推荐

如何将一个enum类型类型转换为另一个类型?

InetPton()函数无效的IP地址

如果实际的syscall是CLONE(),那么为什么strace接受fork()呢?

由Go调用E.C.引起的内存快速增长

括号中的堆栈实现错误问题

在函数中使用复合文字来初始化C语言中的变量

正在try 将文件/文件夹名从目录 struct 存储到链接列表

在列表中插入Int指针(C)

如何将常量char*复制到char数组

调用mProtection将堆栈上的内存设置为只读,直接导致程序SIGSEGV

如何用c语言修改shadow文件hash部分(编程)?

指向不同类型的指针是否与公共初始序列规则匹配?

如何用C语言为CLI应用程序编写按键检测系统?

无法访问共享目标文件内的共享指针

当我在34mb的.mp4文件中使用FREAD时,我得到了一个分段错误,我如何解决它?

赋值两侧的后置增量,字符指针

程序打印一些随机空行

无法将字符串文字分配给 C 中的字符数组

传递参数:C 和 C++ 中 array 与 *&array 和 &array[0] 的区别

运行以下 C 程序时出现分段错误