代码之家  ›  专栏  ›  技术社区  ›  Phil Miller

对大小t(即“size of(struct foo)”)的否定该怎么办?

  •  12
  • Phil Miller  · 技术社区  · 15 年前

    我正在处理一些工作中包含表单表达式的代码

    -(sizeof(struct foo))
    

    即否定 size_t 我不清楚C和C++标准在编译器看到的时候需要什么。具体来说,从这里和其他地方看, sizeof 返回类型为的无符号整数值 西泽特 . 当求反无符号整数时,找不到指定行为的任何明确引用。有没有,如果有的话,是什么?

    6 回复  |  直到 9 年前
        1
  •  21
  •   John Millikin    15 年前

    ISOC和ISO C++标准保证无符号算术是模2。 n -也就是说,对于任何溢出或下溢,它都会“环绕”。对于ISO C++,这是3.91[Basic .Basic ] /4:

    无符号整数,已声明 unsigned ,应遵守算术模2的规律。 n 哪里 n 是特定整数大小的值表示形式中的位数。 四十一

    41)这意味着无符号算术不会溢出,因为结果不能由生成的无符号整数表示。 类型是约化的模到一个大于可以用得到的无符号整数表示的最大值的数字 类型。

    对于ISO C(99),它是6.2.5/9:

    涉及无符号操作数的计算永远不会溢出,因为无法用生成的无符号整数类型表示的结果被缩减为比生成的类型可以表示的最大值大一个数的模。

    这意味着结果保证与 SIZE_MAX - (sizeof(struct foo)) + 1 .


    在ISO 14882:2003 5.3.1.7中:

    […]无符号的负数 数量是通过减去 它的值从2开始 n 在哪里 n 是位的数目 主动操作数。类型 结果是提升的类型 操作数。

        2
  •  2
  •   John Millikin    15 年前

    http://msdn.microsoft.com/en-us/library/wxxx8d2t%28VS.80%29.aspx

    无符号量的一元求反 通过减去值来执行 从2开始的操作数 n ,其中n是 对象中的位数 给定的无符号类型。(微软C++) 在使用 二的补码运算。在其他 处理器,否定的算法 可以不同。

    换句话说,确切的行为将是特定于体系结构的。如果我是你,我会避免使用这种奇怪的结构。

        3
  •  2
  •   Ste    15 年前

    求反无符号数对于在单词间传播LSB以形成后续按位操作的掩码很有用。

        4
  •  1
  •   Chad Simpkins    15 年前

    我唯一能想到的是,这件事是如此的错误,以至于我的头受伤了…

    size_t size_of_stuff = sizeof(stuff);
    
    if(I want to subtract the size)
        size_of_stuff = -sizeof(stuff);
    
    size_t total_size = size_of_stuff + other_sizes;
    

    溢出是一个特性!

        5
  •  1
  •   Phil Miller    15 年前

    来自 current C++ draft standard 第5.3.1节第8句:

    一元的操作数 - 运算符应具有算术或枚举类型,结果为其操作数的负数。整数提升是对整数或枚举操作数执行的。无符号数量的负数是通过从2减去其值来计算的。 n ,其中n是提升操作数中的位数。结果的类型是提升操作数的类型。

    因此,得到的表达式仍然是无符号的,并按照描述进行计算。

    用户@outis在评论中提到了这一点,但我会把它放在一个答案中,因为outis没有。如果outis回来回答,我会接受它。

        6
  •  1
  •   Keith Thompson    9 年前

    size_t 是实现定义的无符号整数类型。

    否定A 尺寸 价值 可能 给你一个类型的结果 西泽特 通常的无符号模行为。例如,假设 西泽特 是32位 sizeof(struct foo) == 4 然后 -sizeof(struct foo) == 4294967292 或2 32 - 4。

    除了一元 - 操作员应用 整型提升 (c)或 整型提升 (c++)(它们本质上是同一事物)的操作数。如果 西泽特 至少和 int ,那么这个提升什么也不做,结果是 尺寸 . 但是如果 int 宽于 西泽特 ,这样 INT_MAX >= SIZE_MAX ,然后是的操作数 - “提升”自 西泽特 int .在这种不太可能的情况下, -sizeof(struct foo) == -4 .

    如果将该值赋回 西泽特 对象,然后将其转换回 西泽特 屈服于 SIZE_MAX-4 你所期望的价值。但是如果没有这样的转换,你会得到一些令人惊讶的结果。

    我从来没有听说过 西泽特 比…窄 int 所以你不太可能碰到这个。但这里有一个测试用例,使用 unsigned short 作为对假设狭隘的支持 西泽特 类型,说明潜在问题:

    #include <iostream>
    int main() {
        typedef unsigned short tiny_size_t;
        struct foo { char data[4]; };
        tiny_size_t sizeof_foo = sizeof (foo);
        std::cout << "sizeof (foo) = " << sizeof (foo) << "\n";
        std::cout << "-sizeof (foo) = " << -sizeof (foo) << "\n";
        std::cout << "sizeof_foo = " << sizeof_foo << "\n";
        std::cout << "-sizeof_foo = " << -sizeof_foo << "\n";
    }
    

    我的系统输出(16位 short ,32位 int 和64位 西泽特 是:

    sizeof (foo) = 4
    -sizeof (foo) = 18446744073709551612
    sizeof_foo = 4
    -sizeof_foo = -4