[英]gcc 7.2: warning: left shift count >= width of type
即使我将每个正确的操作数都强制转换为unsigned long long
,警告仍然存在。 uint8_t << uint64_t
是否应该具有这样的隐式转换: (uint64_t) uint8_t << uint64_t
?
这个答案表明我可以提升两个操作数中的任何一个,整个表达式都将转换为unsigned long long
,但这可能是错误的。
bool dgBioReadU64LE(DgBioFile *file, uint64_t *x) {
uint8_t u[8];
if (!dgBioReadU8v(file, LEN(u), u)) return false;
*x = u[0]|(u[1]<<8ULL)|(u[2]<<16ULL)|(u[3]<<24ULL)|(u[4]<<32ULL)|(u[5]<<40ULL)|(u[6]<<48ULL)|(u[7]<<56ULL);
return true;
}
bool dgBioReadU64BE(DgBioFile *file, uint64_t *x) {
uint8_t u[8];
if (!dgBioReadU8v(file, LEN(u), u)) return false;
*x = u[7]|(u[6]<<8ULL)|(u[5]<<16ULL)|(u[4]<<24ULL)|(u[3]<<32ULL)|(u[2]<<40ULL)|(u[1]<<48ULL)|(u[0]<<56ULL);
return true;
}
uint8_t << uint64_t
是否应该具有这样的隐式转换:(uint64_t) uint8_t << uint64_t
?
TL; DR-不,移位运算符很特殊。
完整答案
您描述的行为(本质上是匹配的操作数类型)在C标准中称为通常的算术转换 。 1个
我们看到该标准对许多运营商(例如,加性运营商)强制执行以下操作:
[6.5.6]如果两个操作数都具有算术类型,则对它们执行常规的算术转换。
但是,对于等价移位运算符,我们在等效部分中没有看到这样的短语。 我们最接近的是:
[6.5.7]对每个操作数执行整数提升。 结果的类型是提升后的左操作数的类型。
但是, 整数提升是另一回事 -他们(基本上)说,将小于[unsigned] int
任何类型都转换为[unsigned] int
。
因此,编译器在此处发出警告是正确的。 (而且,我敢肯定,您可以猜到,解决方案是对左侧操作数执行显式转换;)
1.为了这个答案,我考虑使用C11(特别是N1570 )规范。 行为至少与C99相同。
这个答案表明我可以提升两个操作数中的任何一个,并且整个表达式将长时间转换为无符号,但是这可能是错误的。
它是。
该标准说:
6.5.7 按位移位运算符
对每个操作数执行整数提升。 结果的类型是提升后的左操作数的类型。 如果右操作数的值为负或大于或等于提升的左操作数的宽度,则行为不确定
这意味着您需要强制转换左操作数,而强制转换右操作数在这里不会发生任何变化。
您链接的答案具有误导性。 似乎建议您加宽任何一个操作数,它将触发另一操作数自动转换为普通(更宽)类型。 对于C中的大多数二进制运算符而言,这是正确的。但是,对于移位运算符而言,则并非如此。
在这方面,C中的移位运算符实际上很特殊 。 它们的行为不对称。 将右操作数的类型更改为较宽的类型不会触发将左操作数转换为右操作数的类型,并且不会影响结果类型。 结果类型始终由左操作数的(可能是提升的)类型定义。
在您的情况下,您必须专门将左操作数转换为unsigned long long
类型。
左右移位运算符的结果与左操作数的类型相同。 因此,正确的操作数的类型不会影响结果的类型。
您需要将左操作数强制转换为unsigned long long
以获得所需的结果。
即使我将每个正确的操作数都强制转换为
unsigned long long
,警告仍然存在。uint8_t << uint64_t
是否应该具有这样的隐式转换:(uint64_t) uint8_t << uint64_t
?
没有。
这个答案表明我可以提升两个操作数中的任何一个,整个表达式都将转换为
unsigned long long
,但这可能是错误的。
我明白了您为什么认为链接的答案这么说,但是它证明了使用unsigned long long
类型的常量作为左操作数。 那部分是正确的。 在某种程度上,答案表明可以通过在右侧使用更大的类型来实现相同的目的,这具有误导性。
该标准规定:
对每个操作数执行整数提升。 结果的类型是提升后的左操作数的类型。 如果右操作数的值为负或大于或等于提升的左操作数的宽度,则行为是不确定的。
( C2011,6.5.7 / 3 )
注意清楚,结果表达式的类型是由左操作数的类型来确定唯一,并且它是相对于(促进)型的左操作数的可以触发这个特定undefinedness规定右操作数的值 。
您正在将uint8_t
左移。 整数提升将在左边的操作数上执行,结果是int
类型的值。 假设您的int
为32位宽,左移32位或更多位会产生未定义的行为,并且在某些情况下,由于它是带符号的 ,而不是无符号的int,因此您可能会得到其他未定义的行为。
通过强制转换左操作数来纠正此问题。 例如, (uint64_t) u[7] << 56
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.