【问题标题】:What type is a macro considered? [duplicate]考虑什么类型的宏? [复制]
【发布时间】:2016-02-13 01:08:13
【问题描述】:

如果我将宏定义为#define LOGIC_ONE 1 并希望在case 语句中使用LOGIC_ONE,那么LOGIC_ONE 考虑什么类型?

它是否被识别为 int,因为我将它定义为值 1?

【问题讨论】:

  • 要查看预处理器的作用,请将-E 传递给编译器。 (msvc, gcc, clang 都接受-E)

标签: c++ macros


【解决方案1】:

C++ 宏是简单的文本替换。

在编译器启动时,您的LOGIC_ONE 已经被预编译器替换为1。就像您马上写1一样。 (在这种情况下,它是一个 int 文字......)

编辑以将讨论包含在 cmets 中:
如果您(或其他有权访问您的代码的人)将您的 #define LOGIC_ONE 1 更改为 #define LOGIC_ONE "1",它将在您的程序中更改其行为并成为 const char[] 文字。

编辑:
由于这篇文章得到的关注超出了我的预期,我想我为那些好奇的人添加了对C++ 14 Standard 的引用:

2.2 翻译阶段 [lex.phases]
(...)
4. 执行预处理指令,扩展宏调用,并 _Pragma 一元运算符表达式被执行。 (...) 然后删除所有预处理指令。
(...)
7. 分隔标记的空白字符不再重要。每个预处理令牌都被转换为一个令牌。 (2.6)。生成的标记在句法和语义上进行分析并作为翻译单元进行翻译。

如上所述,宏在第 4 阶段被替换,之后不再存在。 “句法和语义”分析发生在第 7 阶段,代码被编译(“翻译”)。

整数字面量在

中指定

2.13.2 整数字面量 [lex.icon]
(...)
整数文字是没有句点或指数部分的数字序列,可选的分隔单引号在确定其值时会被忽略。整数文字可能有一个指定其基数的前缀和一个指定其类型的后缀。
(...)

表 5 - 整数字面量的类型

   Suffix    |    Decimal literal     | Binary, octal, or hexadecimal literal  
-----------------------------------------------------------------------------
none         | int                    | int
             | long int               | unsigned int
             | long long int          | long int
             |                        | unsigned long int
             |                        | long long int
             |                        | unsigned long long int
-----------------------------------------------------------------------------
u or U       | unsigned int           | unsigned int
             | unsigned long int      | unsigned long int
             | unsigned long long int | unsigned long long int
-----------------------------------------------------------------------------
l or L       | long int               | long int
             | long long int          | unsigned long int
             |                        | long long int
             |                        | unsigned long long int
-----------------------------------------------------------------------------
Both u or U  | unsigned long int      | unsigned long int
and l or L   | unsigned long long int | unsigned long long int 
-----------------------------------------------------------------------------
ll or LL     | long long int          | long long int
                                      | unsigned long long int
-----------------------------------------------------------------------------
Both u or U  |unsigned long long int  | unsigned long long int
and ll or LL |                        |

字符串字面量在

中指定

2.13.5 字符串字面量 [lex.string]
(...)
1 字符串文字是由双引号包围的字符序列(如 2.13.3 中所定义),可选前缀为 R、u8、u8R、u、uR、U、UR、L、rLR,如“... ", R"(...)", u8"...", u8R"**(...)**", u"...", uR"*~(...)*~" 、U"..."、UR"zzz(...)zzz"、L"..." 或 LR"(...)"。
(...)
6 在翻译阶段 6 之后,不以编码前缀开头的字符串文字是普通字符串文字,并使用给定的字符进行初始化。
7 以 u8 开头的字符串文字,例如 u8"asdf",是 UTF-8 字符串文字。
8 普通字符串文字和 UTF-8 字符串文字也称为窄字符串文字。窄字符串字面量的类型为“array of n const char”,其中 n 是字符串的大小,定义如下,并且具有 静态存储持续时间 (3.7)。

【讨论】:

  • 即我可以把LOGIC_ONE 当作int 对待?
  • @Noobgineer 对于当前值是,但是如果有人将其更改为 "1"
  • 你可以用任何你可以对待1的方式对待它——所以是的,它是一个int字面量。
  • @DanielA.White 你是什么意思?将什么更改为"1"
  • @user4581301 不,它会变成const char []
【解决方案2】:

预处理器定义没有类型——它们基本上只是“粘贴”到它们出现的代码中。例如,如果你在语句中使用它;

int foo = LOGIC_ONE;

然后它将被解释为整数。 (在预处理器之后运行的编译器只会将该代码视为int foo = 1;)您甚至可以在诸如;

int foo##LOGIC_ONE;

然后您将创建一个变量foo1。呸!

举一个宏定义的替代例子;

#define LOGIC_ONE hello
int LOGIC_ONE = 5;
printf("%d\n", hello);

这是完全有效的,并声明了一个名为 hello 的 int,但表明没有用于定义的“类型”——hello 只是在代码中遇到 LOGIC_ONE 的地方被替换。

除非绝对必要,否则避免使用预处理器宏。专业编码标准经常禁止或严格限制预处理器的使用。通常总有比使用宏更好的方法来做事。例如,考虑这些替代方案;

static const int LOGIC_ONE = 1;
enum { LOGIC_ONE = 1 };

预处理器是学习者在 C 语言中陷入真正混乱的一种快速方法。

【讨论】:

  • 感谢您的详细解释。这些宏是作为我必须使用且不允许修改的 API 的一部分提供的,但我会听取您的建议,避免使用预处理器宏以备将来使用!
  • 我认为令牌粘贴仅适用于宏参数,一般不适用于宏?
  • 在 C++ 中,除了非常有限的宏使用之外,反对任何东西的建议是 10 倍(这个问题被标记)。几乎可以肯定,您可以使用宏实现更好的类型安全方式。文件包含、包含守卫和条件编译是预处理的剩余主要部分。
【解决方案3】:

LOGIC_ONE 在它出现的任何地方都被 1 替换。就编译器而言,LOGIC_ONE 不存在,它只看到 1。所以你的问题是“1 是 int 吗?”。答案是 -> 这取决于你在哪里输入 1

【讨论】:

  • 好的。我不知道编译器是在寻找1 还是LOGIC_ONE。感谢您的澄清!
【解决方案4】:

宏是文本替换。 1 的类型为 constexpr int

【讨论】:

    猜你喜欢
    • 2011-03-04
    • 2011-05-20
    • 1970-01-01
    • 2013-05-17
    • 2019-10-11
    • 1970-01-01
    • 2019-08-10
    • 2014-04-30
    • 1970-01-01
    相关资源
    最近更新 更多