【问题标题】:Behaviour of sizeof() in C (GCC)C (GCC) 中 sizeof() 的行为
【发布时间】:2013-05-30 09:46:00
【问题描述】:

在回答有关 sizeof() 的问题时,为了了解 GCC 的处理方式,我编写了以下代码:

#include<stdio.h>
#include<stddef.h>
#include<limits.h>

int main(int ac, char *argv[])
{
    printf("%zu\n", sizeof(9999999999999999999999999999999999999999999999999999) );
    printf("%zu %zu \n", sizeof(int), sizeof(long long));
    return 0;
}

编译时,GCC (4.1.2) 发出警告(如预期):

t.c:8:24: warning: integer constant is too large for its type
t.c: In function main:
t.c:8: warning: integer constant is too large for long type

输出是:

16
4 8

GCC 怎么说 sizeof(9999999999999999999999999999999999999999999999999999) 是 16 ?!不管numnber 有多大,对于任何大于LLONG_MAX 的整数文字,它总是16。在我的 64 位平台上,sizeof(long) 等于 sizeof(long long)

为什么 GCC 会这样?这是某种未定义的行为吗?!

【问题讨论】:

  • 顺便说一下,sizeof 不是一个函数,所以它真的不应该拼写为 sizeof(),因为这意味着它是。
  • @unwind:据我所知,你不能拥有sizeof long longsizeof(T) 很常见也很好。
  • @unwind 我知道 sizeof() 不是函数,而是运算符。但我认为提到 sizeof() 没有任何问题。
  • 更不用说没有括号,它是模棱两可的。 sizeof 1 + 1 -> sizeof(1) + 1sizeof(1 + 1)?
  • 这不是实际上模棱两可的:语法说明了如何解析它。不过,这是个坏主意,因为 people 无法直截了当。 :-) [保持直截了当的技巧,顺便说一句:如果它被解析为 (sizeof (1 + 1)),那么 sizeof(1) + 1 仍然是 sizeof expr + expr 仍然是 (sizeof ((1) + 1))。所以它必须意味着 ((sizeof 1) + 1)。]

标签: c gcc sizeof


【解决方案1】:

gcc 有一个特殊的非标准类型,称为__int128,它是一个 128 位(16 字节)整数。所以sizeof(__int128) 将返回 16。看起来你的超大常量就像__int128 类型一样处理。考虑以下代码:

typeof(9999999999999999999999999999999999999999999999999999) (*funcptr_a)();
unsigned  __int128 (*funcptr_b)();

void dummy() {
    funcptr_a = funcptr_b;
}

如果我更改 funcptr_a 和 funcptr_b 声明中的任何类型,赋值 funcptr_a = funcptr_b; 会触发警告。对于这种变化,我没有收到警告(64 位 Linux 上的 gcc 4.6.3),因此我知道大整数常量的类型是 unsigned __int128

顺便说一句,使用 clang 3.0(也是 64 位 Linux)您的代码输出

8
4 8

我想说这不是未定义的,而是实现定义的行为。引用 C99 标准(第 6.4.4.1 节,第 56 页):

[...] 如果一个整数常量不能用它的列表中的任何类型表示,它可能有一个 扩展整数类型,如果扩展整数类型可以表示它的值。 [..]

【讨论】:

  • 有时也可以使用 C11 的 _Generic 以某种方式确认编译器为特定表达式推断的类型,但您的函数赋值是一个不错的技巧。
【解决方案2】:

我们可以问 gcc 本身:

__typeof__ (9999999999999999999999999999999999999999999999999999) var = 1;
printf("%lld\n", var);
sizes.c:10:5: warning: format ‘%lld’ expects argument of type ‘long long int’, but argument 2 has type ‘__int128’ [-Wformat]

因此 gcc 选择 - 如果支持 - 类型 __int128 用于太大的十进制常量。

【讨论】:

    【解决方案3】:

    什么东西这么神秘?这是最大类型的大小。你被警告了。

    标准所保证的只是各种类型的相对大小。

    1 == sizeof(char)

    【讨论】:

    • 在我的平台上 sizeof(long long) 是 8,而不是上面输出中显示的 16。我的问题是关于给 sizeof(99999999999999999999999) 的 16 个。
    • 这没有回答问题。
    • 该死!应该在+3时删除。 :(
    【解决方案4】:

    gcc 可能使用long double 类型来处理非常大的数字,它在 Intel 处理器上使用 80 位。所以它可能将它存储在一个 128 位的数字中:你应该检查sizeof(long double)

    注意:我明确提到 gcc 是因为 Visual C++ 没有这样做(它的 long double 类型与 double 相同)。

    编辑: 结果不是long double(并且根据标准C99 6.4.4.1 alinea 6 on integer constants(第56页),是不允许的)。请参阅 CliffordVienna 和 Daniel Fischer 的回答。

    【讨论】:

    • 因为它太大了,无法放入long long
    • @KingsIndian:标准没有要求。
    • @KingsIndian:C99 标准说(第 6.4.4.1 节):“如果整数常量不能由其列表中的任何类型表示,它可能具有扩展整数类型,如果扩展整数类型可以表示它的值。" 扩展类型是实现定义的。可能有一个 GCC 标志可以禁用这种事情。
    【解决方案5】:

    是的,这并不神秘。对于 GCC 64 位,longlong long 的大小均为 8 字节。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-12-15
      • 2020-08-28
      • 2012-08-27
      • 1970-01-01
      • 2012-04-20
      • 2014-12-26
      • 2013-05-17
      相关资源
      最近更新 更多