我对C ++还是很陌生,但是我发现auto
的这种行为很奇怪:
class A{};
int main() {
A a;
auto x = -(sizeof(a));
cout << x << endl;
return 0;
}
在这种情况下,变量x是unsigned
,尽管我在变量初始化时使用了一元减号运算符。为何只考虑返回类型sizeof
(std::size_t
),却不考虑存储的数字由于使用了运算符而为负的事实呢?
我知道size_t
是一个无符号整数。
我已经在GCC 8.1.0和C ++ 17上进行过尝试。
答案 0 :(得分:29)
此处的实际问题是,与其他内置算术运算符一样,一元减运算符的使用也受积分提升的约束。因此,令人惊讶的是,对size_t
施加一元负数的结果仍然是size_t
,并且无需怪罪auto
。
反例。在这种情况下,由于积分促销的类型,x
将是int
,因此输出将是-1
:
unsigned short a{1};
auto x{-a};
cout << x << endl;
答案 1 :(得分:21)
您的表达式-(sizeof(a))
将一元-
运算符应用于无符号类型的值。一元运算符不会将无符号整数值转换为有符号整数;而是定义哪个无符号值将是如下操作的结果(参见unary arithmetic operators at cppreference.com):
内置一元减运算符计算其负数 提升操作数。对于无符号a,-a的值为2 ^ b -a,其中b是升级后的位数。
因此,即使令人惊讶,auto
仍可正常工作,因为将一元-
运算符应用于无符号值的结果仍然是无符号值。
答案 2 :(得分:4)
将(一元)-
应用于无符号值的结果是无符号的,并且sizeof
返回无符号值。
一元运算符的操作数应具有算术或无作用域 枚举类型,结果是其操作数的取反。 积分提升是对整数或枚举操作数执行的。 无符号数量的负数通过减去它的负数来计算 从2 ^ n开始的值,其中n是提升后的操作数中的位数。 结果的类型就是提升的操作数的类型。
sizeof
和sizeof...
的结果是类型常量std::size_t
为避免实现定义的行为,您必须在应用int
之前转换为-
如果目标类型是带符号的,则该值可以保持不变 以目标类型表示;否则,值为 实现定义的。
class A{};
int main() {
A a;
auto x = -(int{sizeof(a)});
cout << x << endl;
return 0;
}
答案 3 :(得分:1)
如果我们看一下:https://en.cppreference.com/w/cpp/language/sizeof,则结果为size_t
类型,即unsigned
。您明确需要将其声明为signed int
,以允许使用负值。
您可以编写auto
而不是int
来允许负值。