【发布时间】:2016-01-18 12:24:46
【问题描述】:
显然我对宏的工作原理存在根本性的误解。我认为一个宏只是导致预处理器用替换文本替换 @defined 宏。但显然情况并非总是如此。我的代码如下:
TstBasInc.h
#pragma once
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdarg.h>
#include <time.h>
// copy macro
#define Cpy(ToVar, FrmVar) do { \
errno = strncpy_s(ToVar, sizeof(ToVar), FrmVar, _TRUNCATE); \
if (errno == STRUNCATE) \
fprintf(stderr, "string '%s' was truncated to '%s'\n", FrmVar, ToVar); \
} while(0);
// clear numeric array macro
#define ClrNumArr(ArrNam, ArrCnt) \
for (s = 0; s < ArrCnt; s++) \
ArrNam[s] = 0;
uint32_t s; // subscript
typedef struct {
short C;
short YY;
short MM;
short DD;
} SysDat;
TstMacCmpErr:
#include "stdafx.h"
#include "TstBasInc.h" // test basic include file
#define ARRCNT 3
int main()
{
char Cnd = 'E'; // define to use 'else' path
char ToVar[7 + 1]; // Cpy To-Variable
int IntArr[ARRCNT]; // integer array
Cpy(ToVar, "short") // compiles with or without the semi-colon
if (Cnd != 'E')
// Cpy(ToVar, "short string"); // won't compile: illegal else without matching if
Cpy(ToVar, "short string") // will compile
else
Cpy(ToVar, "extra long string"); // compiles with or without the semi-colon
// the following code shows how I thought the macro would expand to
{ \
errno = strncpy_s(ToVar, sizeof(ToVar), "short str", _TRUNCATE); \
if (errno == STRUNCATE) \
fprintf(stderr, "string '%s' was truncated to '%s'\n", "short str", ToVar);; \
}
if (Cnd == 'E') {
ClrNumArr(IntArr, ARRCNT) // compiles with or without the semi-colon
printf("intarr[0] = %d\n", IntArr[0]);
}
else
printf("intarr[0] is garbage\n");
return 0;
}
结果如下:
string 'extra long string' was truncated to 'extra l'
string 'short str' was truncated to 'short s'
intarr[0] = 0;
正如 cmets 所说,当我在 Cpy(ToVar, "short string"); 之后有一个分号时,它甚至无法编译,因为我收到了 "C2181 illegal else without matching if" 错误。如您所见,我尝试按照in this post 的建议在宏中添加一个do-while,但这没有任何区别。当直接复制宏代码时(即使没有 do-while),该代码也可以正常工作。我原以为只需在宏中添加大括号就可以解决问题,但事实并非如此。它必须与以if 结尾的Cpy 有关,因为ClrNumArr 宏在编译时带有或不带有分号。那么有人能告诉我为什么Cpy 宏不只是替换文本吗?我一定错过了一些简单的东西。
我正在使用 VS 2015 社区版更新 1。
编辑:我记录了问题并将其隔离到(我认为)Cpy 宏中的if 语句。 仍然没有人解释为什么宏没有按照我认为的方式扩展。那应该是帖子的标题,因为这是我的问题,而不是分号的问题,我现在有一个解决方案。
【问题讨论】:
-
不要在宏定义中使用分号。
-
不要在函数可以工作的地方使用宏。
-
见gcc.gnu.org/onlinedocs/cpp/Swallowing-the-Semicolon.html 注意分号实际上是一个空语句
-
0) 如前所述,不要在函数也可以工作的地方使用宏。一个原因只是咬你。 1) 不要尝试过早的优化。编译器和 CPU 可能比你聪明。 2) 如果您的代码确实证明太慢,请使用
inline函数和/或链接时间优化 (LTO)。 3)作为一个初学者,甚至不要考虑这些事情。 -
不要使用 K&R。这甚至不包括 C99,更不用说标准 C(即 C11 - 没有其他有效的 C 标准)。您也不想学习驾驶/使用 Model-T 汽车或前数字手机。