【问题标题】:Maximum/minimum value of #define values [duplicate]#define 值的最大值/最小值[重复]
【发布时间】:2019-03-03 04:47:50
【问题描述】:

在 C 语言中使用 #define 命令时,变量的最大或最小数量是多少?例如,是

#define INT_MIN (pow(-2,31))
#define INT_MAX (pow(2,31))

一个可接受的定义?我想一个更好的方法是问定义值的数据类型是什么?

【问题讨论】:

  • 在 C 中,INT_MININT_MAX 的值在标准头 <limits.h> 中指定,除非您喜欢混淆自己和/或其他程序员,否则定义自己的值不是一个好主意谁需要了解您的代码。 INT_MININT_MAX(或它们产生的值)都允许最小幅度为 32767。所以INT_MIN 保证为-32767 或更少,INT_MAX 保证为32767 或更多。两者的实际值是实现定义的(即编译器和库之间不保证一致性)。

标签: c types


【解决方案1】:

#define 执行令牌替换。如果您不知道标记是什么,您可以将其视为完整单词的文本替换,就像您的编辑器的“搜索和替换”功能可以做的那样。因此,

#define FOO 123456789123456789123456789123456789123456789

到目前为止是完全有效的——这只是意味着预处理器将用那个长数字替换FOO 的每个实例。这样做也是完全合法的(就预处理而言)

#define FOO this is some text that does not make sense

因为预处理器对C一无所知,只是将FOO替换为定义的任何内容。

但这可能不是您要寻找的答案。

在预处理器替换了宏之后,编译器将不得不编译任何留在原处的东西。而且编译器几乎肯定无法编译我在此处发布的任何一个示例并出错。

整数常量可以与编译器定义的最大整数类型一样大,相当于uintmax_t(在<stdint.h> 中定义)。例如,如果此类型为 64 位宽(非常常见的情况),则最大有效整数常量为 18446744073709551615,即 2 的 64 次幂减 1。

这与该常量的编写或构造方式无关——无论是通过#define 完成,还是直接写在代码中,还是以十六进制写,都没有关系。限制是一样的,因为它是编译器给定的,编译器在预处理完成后运行。

编辑:正如@chux 在 cmets 中所指出的,在最新版本的 C(从 C99 开始)中,十进制常量将默认被签名,除非它们带有一个后缀以表明其他情况(例如 U/u,或组合类型/签名后缀,如ULL)。在这种情况下,最大有效的无后缀常量将是任何适合intmax_t 值的值(通常是uintmax_t 最大值的一半向下舍入);带有无符号后缀的常量可以增长到与uintmax_t 值一样大。 (请注意,C 整数常量,无论是否有符号,都不会是负数。)

【讨论】:

  • 谢谢,我现在明白了,这很有意义。
  • "最大有效整数常量是 18446744073709551615" --> 不。预处理器确实理解一些 C 的东西。使用“18446744073709551615u”,添加u
  • 您可以尝试使用我发布的两个愚蠢的#define sn-ps 中的任何一个在文件上运行预处理器(例如,gcc -E);你会看到他们工作。至于常量,您在最新版本的 C 中是正确的。(在 C90 中,这将是有效的;如果不适合其他情况,常量将默认为无符号。令人惊讶的向后不兼容。)
  • Note C90 最多只需要 32 位类型。 18446744073709551615 在常见的 C90 实现中仍然是一个问题。 4294967295 在 C90 和 C99 上很好。
  • @注意,对于 PP 数学,LLL 是无关紧要的。 #define A 1000000000 #define B 8000000000 #if A*8 == B 是真的,即使在 1000000000 上没有 LL - 它仍然是 intmax_t 数学。
【解决方案2】:

#define INT_MIN (pow(-2,31)) 是不可接受的,因为它最多构成错误的类型

pow() 返回一个double

考虑一下:INT_MIN % 2 导致无效代码,因为 % 不能在 double 上完成。

【讨论】:

    【解决方案3】:

    出于多种原因,您的定义是不明智的:

    • 这些宏名称在标准库头文件 limits.h 中使用,它们是为工具链的目标平台正确定义的。

    • 宏不是 C 语言本身的一部分;相反,它们会导致将替换文本插入代码中以供编译器评估;因此,您的定义将导致函数pow() 在使用这些宏的任何地方被调用 - 在运行时(重复)评估而不是编译时常量。

    • 32位二进制补码整数的最大值不是231而是231 - 1.

    • pow() 函数返回 double 而不是整数 - 因此您的宏表达式具有 double 类型。

    • 您的宏假定平台的整数大小为 32 位,但不一定是这种情况 - 定义不可移植。中的那些也可能是这样,但是整个库是特定于平台的,并且您会在每个平台上使用不同的库/工具链。

    如果您必须(而且您真的不应该)为此定义自己的宏,您应该:

    • 使用不同的宏名称定义它们,
    • 没有关于目标平台整数宽度的假设,
    • 使用常量表达式,
    • 使用具有int 类型的表达式。

    例如:

    #define PLATFORM_INDEPENDENT_INT_MAX ((int)(~0u >> 1u)) 
    #define PLATFORM_INDEPENDENT_INT_MIN ((int)~(~0u >> 1u)) 
    

    使用以下代码:

    #include <stdio.h>
    #include <limits.h>
    
    #define PLATFORM_INDEPENDENT_INT_MAX ((int)(~0u >> 1u)) 
    #define PLATFORM_INDEPENDENT_INT_MIN ((int)~(~0u >> 1u)) 
    int main()
    {
        printf( "Standard: %d\t%d\n", INT_MIN, INT_MAX);
        printf( "Mine:     %d\t%d\n", PLATFORM_INDEPENDENT_INT_MIN, PLATFORM_INDEPENDENT_INT_MAX);
    
        return 0;
    }
    

    输出:

    Standard: -2147483648   2147483647                                                                                                                                                 
    Mine:     -2147483648   2147483647  
    

    【讨论】:

      猜你喜欢
      • 2013-11-11
      • 1970-01-01
      • 2023-03-18
      • 1970-01-01
      • 2021-06-12
      • 2020-03-10
      • 1970-01-01
      • 1970-01-01
      • 2021-04-16
      相关资源
      最近更新 更多