使用代码:
#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()中,我首先将其分配给变量,然后没有警告。
(只有当c ++时,clang才会发出警告)
具有以上内容的编译器资源管理器:https://godbolt.org/z/q9eMVT
答案 0 :(得分:2)
我认为这是GCC中的错误。基于[expr.ass]/7,表达式
x |= y
等同于
x = x | y
除了a
仅被评估一次。如上面的CoryKramer注释中所述,在按位或运算中,就像其他按位运算一样,通常将首先在两个操作数[expr.or]/1上执行常规的算术转换。由于我们两个操作数的类型均为std::uint8_t
,因此通常的算术转换只是积分提升[expr.arith.conv]/1.5。在std::uint8_t
上进行整数提升应该意味着将两个操作数都转换为int
[conv.prom]/1。不需要进一步转换操作数,因为两个操作数的转换类型相同。最后,由int
表达式产生的|
然后被转换回std::uint8_t
并存储在x
[expr.ass]/3所引用的对象中。我认为在某些情况下,这是触发警告的最后一步。但是,无论我们是否转换为std::uint8_t
(is guaranteed to be larger,std::uint8_t
中两个int
之间按位逻辑OR的结果都不可能在a()
中表示。 }},然后再返回。因此,这里不需要发出警告,这可能就是为什么通常不发出警告的原因。
我看到的第一个版本和第二个版本之间的唯一区别是d
是一个右值,而c = c | a()
是一个左值。但是,值类别不应影响常规算术转换的行为。因此,警告(无论是否必要)至少应始终如一地发出。如您所知,其他编译器(例如clang)在此处不会发出警告。此外,这个问题似乎是函数调用涉及复合分配的一个奇怪的特定问题。正如SergeyA在上面的另一条评论中所指出的那样,GCC将不会以c |= static_cast<std::uint8_t>(42);
的等效形式生成警告。使用其他种类的右值代替函数调用,例如,转换文字的结果
c |= (a(), static_cast<std::uint8_t>(5));
will also not produce a warning in GCC。但是,只要在表达式的右侧有一个函数调用,即使该函数调用的结果根本没有使用,例如,在
create table #temp
( STUDENT_KEY INT identity (10000000,1),
STUDENT_ID AS CONCAT('STD',STUDENT_KEY),
STUDENT_FIRSTNAME VARCHAR(255),
STUDENT_SURNAME VARCHAR(255)
)
INSERT INTO #temp
VALUES ( 'Daenerys' , 'Targaryen' ),
( 'Jon' , 'Snow' ),
( 'Gregor' , 'Clegane' ),
( 'Arya' , 'Stark' ),
( 'Cersei' , 'Lannister' ),
( 'Joffrey' , 'Baratheon' ),
( 'Petyr' , 'Baelish' ),
( 'Khal' , 'Drogo' ),
( 'Theon' , 'Greyjoy' ),
( 'Ramsey' , 'Bolton' )
SELECT * FROM #temp
the warning appears。因此,我得出的结论是,这是GCC中的错误,如果您愿意write a bug report,那就太好了。 …