【问题标题】:Type of #define variables#define 变量的类型
【发布时间】:2012-01-24 22:39:21
【问题描述】:

如果我有:

#define MAXLINE    5000

MAXLINE 被理解为什么类型?我应该假设它是int 吗?我可以测试一下吗?

一般来说,如何确定#defineed 变量的类型?

【问题讨论】:

    标签: c c-preprocessor


    【解决方案1】:

    它没有类型。这是一个简单的文本替换。文本 5000 将被放置在 MAXLINE 作为标记出现的任何位置。

    例如:

    int a = MAXLINE;
    

    会将值 5000 放入 a

    虽然

    char *MAXLINE2 = "MAXLINE";
    

    不会导致

    char *50002 = "5000";
    

    因此,如果您想要进行类型检查,那么宏不是可行的方法。您将需要声明静态常量,这样编译器就会完成类型检查。

    有关staticconst#define之间区别的信息,有很多来源,包括这个问题:Static, define, and const in C

    【讨论】:

    • 在算术运算期间,数据类型#define 常量被提升为(我的意思是隐式转换)。如果它们大于整数类型,是否会在末尾使用后缀 L 或 LL 截断?同样,如果我使用浮点数(#define FLT_VAR 3.0),这会被视为浮点数还是双精度数?
    【解决方案2】:

    MAXLINE 根本不是变量。事实上,它不是 C 语法。编译过程的一部分在编译器之前运行预处理器,预处理器执行的操作之一是将源文件中的 MAXLINE 标记的实例替换为 #define MAXLINE 之后的任何内容(问题代码中的 5000)。

    另外:在代码中使用预处理器的另一种常见方式是使用 #include 指令,预处理器只需将其替换为包含文件的预处理内容。

    示例

    让我们看一个实际的编译过程示例。这是一个文件foo.c,将在示例中使用:

    #define VALUE 4
    
    int main()
    {
      const int x = VALUE;
      return 0;
    }
    

    我使用gcccpp (the C preprocessor) 作为示例,但是您可以使用任何编译器套件来执行此操作,当然,使用不同的标志。

    编译

    首先,让我们编译foo.cgcc -o foo.c。发生了什么?有效;你现在应该有一个可执行文件foo

    仅预处理

    您可以告诉gcc 只进行预处理而不进行任何编译。如果您执行gcc -E foo.c,您将获得标准输出的预处理文件。这是它产生的结果:

    # 1 "foo.c"
    # 1 "<built-in>"
    # 1 "<command-line>"
    # 1 "foo.c"
    
    
    int main()
    {
      const int x = 4;
      return 0;
    }
    

    注意main 的第一行已将VALUE 替换为4

    您可能想知道前四行是什么。这些被称为线标记,您可以在Preprocessor Output 中阅读有关它们的更多信息。

    无需预处理即可编译

    据我所知,您不能直接跳过 gcc 中的预处理,但是有几种方法可以告诉它文件已经被预处理。但是,即使您这样做,它也会删除文件中存在的宏,因为它们不是供编译器使用的。您可以使用gcc -E -fpreprocessed foo.c 查看编译器在这种情况下的作用:

    .
    .
    .
    .
    int main()
    {
      const int x = VALUE;
      return 0;
    }
    

    注意:我把点放在顶部;假装那些是空行(我不得不把它们放在那里让这些行被 SO 显示)。

    这个文件显然不会编译(尝试gcc -fpreprocessed foo.c 找出答案)因为VALUE 存在于源代码中,但未在任何地方定义。

    【讨论】:

      【解决方案3】:

      我们称之为宏或预处理器,用于对源文件内容进行字符串替换。阅读:https://en.wikipedia.org/wiki/C_macro

      【讨论】:

      • 详细说明:#define 由“预处理器”处理,“预处理器”的意思是“它在编译器看到源文本之前对其进行处理”。 tpg2114 说的是正确的:编译器理解“类型”。预处理器在此之前参与 - 这是简单的文本替换。仅此而已。
      【解决方案4】:

      编译器永远不会看到那行代码,预处理器会在实际编译之前运行,并将这些宏替换为它们的字面值,有关更多信息,请参见下面的链接

      http://www.cplusplus.com/doc/tutorial/preprocessor/

      【讨论】:

        【解决方案5】:

        它没有类型。它只是一个标记,预处理器在将代码传递给编译器之前将其放入源代码中。你可以做这个(荒谬的)事情来声明一个名为x5000的变量:

        #define APPEND(x,y) x ## y
        
        int main() {
                int APPEND(x,5000);
                x5000 = 3;
        }
        

        预处理器在将其传递给编译器之前将其转换为 this:

        int main() {
                int x5000;
                x5000 = 3;
        }
        

        因此,仅仅因为您在宏中看到 5000,并不意味着它必须是数字。

        【讨论】:

          【解决方案6】:

          (非常!)广义地说,您的 C 编译器在执行时将执行 3 个任务:

          1. 对源文件运行预处理传递,

          2. 在预处理的源文件上运行编译器

          3. 在生成的目标文件上运行链接器。

          # 开头的行,如行

          
          #define MAXLINE    5000
          

          由预处理器阶段处理。 (简单地说)预处理器将解析文件并对其检测到的任何宏执行文本替换。预处理器中没有类型的概念。

          假设您的源文件中有以下几行:

          
          #define MAXLINE    5000
          int someVariable = MAXLINE;     // line 2
          char someString[] = "MAXLINE";  // line 3
          

          预处理器将在第 2 行检测到宏 MAXLINE,并将执行文本替换。请注意,第 3 行 "MAXLINE" 不被视为宏,因为它是字符串文字。

          预处理阶段完成后,编译阶段只会看到以下内容:

          
          int someVariable = 5000;        // line 2
          char someString[] = "MAXLINE";  // line 3
          

          (为清楚起见,cmets 已保留,但通常由预处理器删除) 您可能可以在编译器上使用一个选项来检查预处理器的输出。在 gcc 中,-E 选项将执行此操作。

          请注意,虽然预处理器没有类型的概念,但没有理由不能在宏中包含类型以确保完整性。例如

          
          #define MAXLINE    ((int)5000)
          

          【讨论】:

            【解决方案7】:

            是的,您可以假设它是int

            嗯,实际上所有其他答案都是正确的。不是C,只是 告诉预处理器做一些文本的指令 替换,因此它没有类型。但是,如果您不执行任何操作 用它做一些时髦的事情(比如##预处理器技巧),你会 通常使用MAXLINE 像某种常量,以及预处理器 将用5000 替换它,这确实是一个显式常量。和 常量确实有类型:5000int。一个常数写成 十进制整数,没有后缀(如 U 或 L),将被解释为 编译器为intlong intunsigned long int:第一个 这些类型中最适合的。

            但这当然与前任无关。你可以 将您的问题改写为“5000 的类型是什么?”,没有 #define.

            【讨论】:

              猜你喜欢
              • 2019-06-19
              • 2019-11-03
              • 1970-01-01
              • 2011-12-30
              • 1970-01-01
              • 2020-04-21
              • 2015-03-27
              • 1970-01-01
              • 2016-06-10
              相关资源
              最近更新 更多