【问题标题】:Any guaranteed minimum sizes for types in C?C中类型的任何保证最小尺寸?
【发布时间】:2010-12-16 20:25:05
【问题描述】:

您通常可以对数据类型的最小大小做出任何假设吗?

到目前为止我读过的内容:

  • 字符:1 个字节
  • 短:2 字节
  • int:2 字节,通常为 4 字节
  • 长:4 字节

浮动???双???

float.hlimits.h 中的值是否依赖于系统?

【问题讨论】:

    标签: c types cross-platform


    【解决方案1】:

    这在Wikipedia article:

    short int 不得大于 int
    int 不得大于 long int

    short int 的长度必须至少为 16 位。
    int 的长度必须至少为 16 位。
    long int 的长度必须至少为 32 位。
    long long int 的长度必须至少为 64 位。

    该标准并不要求这些尺寸中的任何一个都必须不同。这是完全有效的,例如,如果所有四种类型都是 64 位长。

    【讨论】:

    • 有一个常见的误解,即 char = byte = 8-bits。如this answer中所述,char很可能是其他大小(如64位)。 sizeof 仅测量给定数据类型中的“可以容纳多少个字符”。 (所以 sizeof(char) == 1 根据定义)
    • @Laurence: char 在这个答案中根本没有讨论?
    • @Jed:我确实没有提到它,但它是包含在答案中的一条很好的信息(尽管它可能更适合作为对该问题的评论)。
    • char 定义为至少 8 位(<limits.h> CHAR_BIT 要求至少为 8)。
    • 此外,POSIX 和 Windows 都要求 CHAR_BIT 为 8,这意味着 CHAR_BIT 在普通桌面/工作站/服务器环境中基本上 为 8。唯一的例外是古老的旧式大型机、DSP,可能还有一些嵌入式系统。
    【解决方案2】:

    是的,float.hlimits.h 中的值取决于系统。您永远不应该对类型的宽度做出假设,但标准确实规定了一些最小值。请参阅C99 standard 中的 §6.2.5 和 §5.2.4.2.1。

    例如,标准只规定char 应该足够大以容纳执行字符集中的每个字符。它没有说它有多宽。

    对于浮点情况,标准提示了类型宽度的给出顺序:

    §6.2.5.10

    有三种真正的浮点类型,分别指定为floatdoublelong 双32)float 类型的值集是 double 类型的值集的子集; double 类型的值集是 long double 类型的值集的子集。

    他们隐含地定义了哪个比另一个更宽,但没有具体定义它们有多宽。 “子集”本身是模糊的,因为 long double 可以具有与 double 完全相同的范围并满足此子句。

    这是非常典型的 C 语言方式,每个单独的环境都留下了很多内容。你不能假设,你必须问编译器。

    【讨论】:

    • 一个字符必须是一个字节。但是一个字节不需要是8位。
    • 附件 F 怎么样?在 F.2.1 中,似乎声明 float 匹配 IEC 60559 单格式,而 double 匹配 IEC 60559 双格式。可悲的是,我没有 60559 可供参考,但(非权威)维基百科似乎指出 60559 单是 32,60559 双是 64。我误读了什么吗?
    【解决方案3】:

    九年了,仍然没有关于float, double, long double最小大小的直接答案。


    C 中的类型有任何保证的最小大小吗?

    对于 浮点 输入 ...

    实用的角度来看,float 的最小大小是 32 位double64 位 . C 允许 doublelong double 共享相似的特征,因此 long double 可以像 double 一样小:Example1 或 80 位或 128 位或 . ..

    我可以想象一个兼容 C 的 48 位 double 可能已经存在——但不知道。


    现在,让我们想象一下,我们富有的叔叔去世了,给我们留下了一笔财富,用于支付 www.smallest_C_float.com 的发展和文化推广。

    C 指定:

    1. float 有限范围至少为 [1E-37…1E+37]。见FLT_MIN, FLT_MAX

    2. (1.0f + FLT_EPSILON) – 1.0f <= 1E-5.

    3. float 支持正负值。

      让 X:数字 1-9 让 Y:数字 0-9 让 E:值 -37 到 36 让 S:+ 或 - 设 b: 0 或 1

    我们的float 可以最低限度地表示SX.YYYYY*10^E 的所有组合,使用基数为 10。

    还需要0.0±1E+37(另外3 个)。我们不需要 -0.0、次法线、±无穷大或非数字。

    即 2910^5*74 + 3 种组合或 133,200,003,需要至少 27 位进行编码 - 不知何故。回想一下,目标是最小尺寸。

    使用经典的 base 2 方法,我们可以假设隐含的 1 并得到 S1.bbbb_bbbb_bbbb_bbbb_b2^e 或 22^17*226 组合或 26 位。

    如果我们尝试以 16 为基数,则需要大约 21516^(4 或 5)*57 个组合或至少 26 到 30 位。

    结论:一个 C float 至少需要 26 位编码。


    A C 的double 不需要比float 表达更大的指数范围,它只是具有不同的最小精度要求。 1E-9.

    S1.bbbb_bbbb_bbbb_bbbb_ bbbb_ bbbb_ bbbb_bb2^e --> 22^30*226 组合或 39 位。


    在我们的 imagine-if-you-will 计算机上,我们可以有一个 13 位的 char 并因此编码 float, double, long double 而没有填充。这样我们就可以实现一个非填充的26位float和39位double, long double


    1Microsoft Visual C++ for x86, which makes long double a synonym for double


    [编辑] 2020

    额外的double 要求可能需要 41 位。可能必须使用 42 位 double 和 28 位 float。将需要审查。大叔会不高兴的。

    【讨论】:

    • 随便。我很高兴我被允许使用 Java,并且无论平台如何,都可以准确地知道一个字节有多少位。我做的是 IBM System Z,所以男孩,我现在疯狂地计数 ;-)
    【解决方案4】:

    但是,新的 C99 指定(在 stdint.h 中)最小尺寸的可选类型,如 uint_least8_tint_least32_t 等。
    (见en_wikipedia_Stdint_h

    【讨论】:

    • 如果您的实现没有 cstdint,请尝试使用 boost 的 cstdint,它将正确的类型放置在 boost 命名空间中。我相信它会委托给实现 cstdint 如果它有一个。
    • @kts,Boost 是一个 C++ 库,问题标记为 C。
    • 在 boost.cstdint 的情况下两者都是。 Cstdint 几乎完全是 typedefs
    【解决方案5】:

    提出此类问题的开发人员通常会处理安排一个打包的struct 以匹配定义的内存布局(如消息协议)。假设语言应直接指定布局 16、24、32 位等字段。

    这对于汇编语言和其他与特定 CPU 架构密切相关的应用程序特定语言来说是常规且可接受的,但有时在可能针对谁知道什么样的架构的通用语言中是一个问题。

    事实上,C 语言并不是为特定的硬件实现而设计的。它通常被指定,以便 C 编译器实现者可以正确地适应特定 CPU 的实际情况。由 9 位字节、54 位字和 72 位内存地址组成的 Frankenstein 硬件架构可以轻松且明确地映射到 C 功能。 (char 是 9 位;short intintlong int 是 54 位。)

    这种普遍性就是为什么 C 规范说“不要对超出 sizeof (char)

    目前的现实是——而且未来似乎也如此——软件要求架构提供 8 位字节,并且内存字可作为单个字节寻址。情况并非总是如此。不久前,我在 CDC Cyber​​ 架构上工作,该架构具有 6 位“字节”和 60 位字。一个 C 实现会很有趣。事实上,该架构负责 Pascal 的奇怪打包语义——如果有人记得的话。

    【讨论】:

    • 在现代 DSP 架构中,最小的可寻址单元通常大于 8 位,例如 32 位。
    • 我没有遇到过这些。我编写的大多数 DSP 都有位寻址存储器。即对于 char *p,表达式 (int)&p[1] - (int)p 为 8。
    • 希望能够绝对指定结构格式是合理的;旨在使代码高效和可移植的语言应该包括这样的功能。由于大端和小端格式的八位字节和 2、4 和 8 组完全支配其他所有内容出于信息交换目的,我认为编译器没有理由任何 平台不应支持具有指定大小和字节序的有符号和无符号固定格式值。使用此类类型的代码在 char 不是 8 位的系统上表现不佳,但如果此类类型...
    • ...主要用于将作为八位字节序列处理的结构,性能不会比解决它们缺失所必需的代码差。
    【解决方案6】:

    如果您不想检查系统/平台上任何类型的大小(字符的倍数)确实是您期望的大小,您可以这样做:

    enum CHECK_FLOAT_IS_4_CHARS
    {
       IF_THIS_FAILS_FLOAT_IS_NOT_4_CHARS = 1/(sizeof(float) == 4)
    };
    

    【讨论】:

    • 嗯?!通常使用断言。例如。断言(sizeof(float) == 4);
    • 'assert' 是一个运行时函数,因此可以评估程序需要运行的语句。如果 sizeof(float) 不是 4,上述语句会在编译时导致错误。
    • struct { char check_float_is_4_chars[2*(sizeof(float)==4)-1]; };
    • #define STATIC_ASSERT(pred) switch(0){case 0:case pred:;}
    • 自C11,static_assert ( sizeof(float)*CHAR_BIT == 32 , "(float) size != 32");
    【解决方案7】:

    C99 N1256 标准草案

    http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1256.pdf

    C99 指定了两种类型的整数保证:

    • 最小尺寸保证
    • 类型之间的相对大小

    相对保证

    6.2.5 类型

    8 对于任意两个具有相同符号和不同整数转换等级的整数类型 (见 6.3.1.1),整数转换等级较小的类型的取值范围是 其他类型值的子范围。

    6.3.1.1 布尔、字符和整数确定相对转换等级:

    1 每个整数类型都有一个整数转换等级,定义如下:

    • long long int 的秩应大于 long int 的秩,即 应该大于int的rank,int的rank应该大于short的rank int,应大于signed char的等级。
    • 任何无符号整数类型的等级应等于相应的等级 有符号整数类型(如果有)。
    • 对于所有整数类型 T1、T2 和 T3,如果 T1 的秩大于 T2 并且 T2 具有 排名大于 T3,则 T1 排名大于 T3

    绝对最小尺寸

    https://stackoverflow.com/a/1738587/895245 提到过,为了方便,这里引用一下。

    5.2.4.2.1 整数类型的大小<limits.h>

    1 [...] 它们的实现定义值的大小(绝对值)应等于或大于所示值 [...]

    • UCHAR_MAX 255 // 2 8 - 1
    • USHRT_MAX 65535 // 2 16 - 1
    • UINT_MAX 65535 // 2 16 - 1
    • ULONG_MAX 4294967295 // 2 32 - 1
    • ULLONG_MAX 18446744073709551615 // 2 64 - 1

    浮点数

    如果定义了 __STDC_IEC_559__ 宏,则保证每种 C 类型的 IEEE 类型,尽管 long double 有几种可能性:Is it safe to assume floating point is represented using IEEE754 floats in C?

    【讨论】:

    • @chux 三分之二让我微笑。你指的是floatdoublelong double吗?我认为它在链接上已经得到了很好的解释。
    • 是的,在 3 种类型中的 2 种有狭义保证:floatdouble
    【解决方案8】:

    引用标准确实给出了被定义为“正确答案”的内容,但它实际上并不能反映程序的一般编写方式。

    人们总是假设 char 是 8 位,short 是 16,int 是 32,long 是 32 或 64,long long 是 64。

    这些假设不是一个好主意,但你不会因为做出这些假设而被解雇。

    理论上,<stdint.h> 可用于指定固定位宽类型,但您必须为 Microsoft 寻找一个。 (See here for a MS stdint.h.) 这里的问题之一是 C++ 在技术上只需要 C89 兼容性就可以成为一个符合要求的实现;即使对于普通 C,C99 甚至在 2009 年也没有得到完全支持。

    char 没有宽度规范也不准确。有,标准只是避免说它是否签名。以下是 C99 的实际含义:

    • 不是位域(字节)的最小对象的位数
      CHAR_BIT 8
    • signed char 类型对象的最小值
      SCHAR_MIN -127 // -(27 - 1)
    • signed char 类型对象的最大值
      SCHAR_MAX +127 // 27 - 1
    • 无符号字符类型对象的最大值
      UCHAR_MAX 255 // 28 - 1

    【讨论】:

    • 这些是最低要求。标准中没有任何内容禁止实现将 CHAR_BIT 定义为9,或1618,...
    • "int 是 32" ---> 嗯。通常在嵌入式 C 中,int 是 16 位的 - 正如 C 规范所允许的那样。 2016 年每年有 1 亿。
    【解决方案9】:

    大多数库都这样定义:

    #ifdef MY_ARCHITECTURE_1
    typedef unsigned char u_int8_t;
    typedef short int16_t;
    typedef unsigned short u_int16_t;
    typedef int int32_t;
    typedef unsigned int u_int32_t;
    typedef unsigned char u_char;
    typedef unsigned int u_int;
    typedef unsigned long u_long;
    typedef unsigned short u_short;
    #endif
    

    然后你可以在你的程序中使用这些 typedef 而不是标准类型。

    【讨论】:

      猜你喜欢
      • 2014-11-19
      • 2012-01-10
      • 2018-02-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-04
      • 2013-05-31
      • 1970-01-01
      相关资源
      最近更新 更多