c++ - 函数返回值的位运算符提升
问题描述
带代码:
#include <cstdint>
uint8_t a() { return 5; }
auto b() {
uint8_t c = 6;
c |= a(); // Warning here
return c;
}
auto d() {
uint8_t c = 6;
uint8_t d = a();
c |= d;
return c;
}
g++ 警告(使用 -Wconversion):
<source>:7:12: warning: conversion from 'int' to 'uint8_t' {aka 'unsigned char'} may change value [-Wconversion]
我假设问题与位操作的整数提升有关,但在第二个函数 d() 中,我首先将它分配给一个变量,然后没有警告。
(clang 不会对此发出警告,只有 g++)
- 这可以通过强制转换而不是变量赋值来解决吗?
- 为什么当我使用函数时它的行为会有所不同?
具有上述内容的编译器资源管理器:https ://godbolt.org/z/q9eMVT
解决方案
我认为这是 GCC 中的一个错误。基于[expr.ass]/7,表达式
x |= y
相当于
x = x | y
除了a
只评估一次。在按位包含的 OR 中,与其他按位运算一样,正如上面 CoryKramer 的评论中所指出的那样,通常的算术转换将首先在两个操作数[expr.or]/1上执行。由于我们的两个操作数都是 type std::uint8_t
,因此通常的算术转换只是整数提升[expr.arith.conv]/1.5。积分提升std::uint8_t
应该意味着两个操作数都转换为int
[conv.prom]/1。不需要进一步转换操作数,因为两个操作数的转换类型相同。最后,表达式的int
结果|
然后被转换回std::uint8_t
并存储在引用的对象中x
[expr.ass]/3。我会假设这最后一步是在某些情况下触发警告的原因。但是,无论我们是否转换为(保证更大)并沿途返回,两者之间的按位逻辑 OR 的结果std::uint8_t
不可能在 中表示。因此,这里不需要警告,这可能是通常不产生警告的原因。std::uint8_t
int
我在您的第一个版本和第二个版本之间看到的唯一区别是它a()
是一个右值,而d
它是一个左值。但是,值类别不应该对通常的算术转换的行为产生影响。因此,警告——无论是否不必要——至少应该始终如一地产生。正如您自己所注意到的,其他编译器(例如 clang)不会在此处产生警告。此外,这个问题似乎奇怪地特定于函数调用在复合赋值中的参与。正如 SergeyA 在上面的另一条评论中所指出的,GCC 不会以c = c | a()
. 使用其他类型的右值代替函数调用,例如,转换文字的结果
c |= static_cast<std::uint8_t>(42);
也不会在 GCC 中产生警告。但是只要在表达式的右侧有一个函数调用,即使函数调用的结果根本没有被使用,例如,在
c |= (a(), static_cast<std::uint8_t>(5));
推荐阅读
- wordpress - 如何创建一个用户提供详细信息的表单,还可以检查他在 wordpress 上输入的内容
- javascript - 如何设置输入类型月份以便在循环月份时自动增加/减少年份?
- scheme - 通过在 Scheme 中折叠来获取列表的“与”
- apache - 如何在 php 7.4 上安装 ziparchive?
- html - 如何在 FullCalendar.io 时间线视图的资源列的一角只显示一种颜色?
- angular - 我想在带有角度材料的动态选项卡中创建一个动态选项卡
- javascript - 如何在 Angular 中通过 REST API 上传 CSV 文件?
- java - Java Hibernate 写入查询以对列表中的值求和
- c - 滚动条滑块行为
- android - 我的应用程序第一次运行,然后每次我尝试重新打开时都会崩溃