为什么“自动”不尊重一元减号运算符?

时间:2018-07-25 08:14:27

标签: c++ sizeof unsigned

我对C ++还是很陌生,但是我发现auto的这种行为很奇怪:

class A{};

int main() {
    A a;
    auto x = -(sizeof(a));
    cout << x << endl;
    return 0;
}

在这种情况下,变量x是unsigned,尽管我在变量初始化时使用了一元减号运算符。为何只考虑返回类型sizeofstd::size_t),却不考虑存储的数字由于使用了运算符而为负的事实呢?

我知道size_t是一个无符号整数。

我已经在GCC 8.1.0和C ++ 17上进行过尝试。

4 个答案:

答案 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是提升后的操作数中的位数。   结果的类型就是提升的操作数的类型。

[expr.unary.op]

  

sizeofsizeof...的结果是类型常量   std​::​size_­t

[expr.sizeof]

为避免实现定义的行为,您必须在应用int之前转换为-

  

如果目标类型是带符号的,则该值可以保持不变   以目标类型表示;否则,值为   实现定义的。

[conv.integral]

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来允许负值。