用下面的c宏替换strncMP(可能还有任何其他函数)中的参数似乎有问题:

#define STRING_WITH_SIZE_MINUS_ONE(x)   x, sizeof(x)-1

...

if (0 == strncmp(str1, STRING_WITH_SIZE_MINUS_ONE("str2")) {
// do something
}

当使用arm-linux-gnueabihf-GCC 4.9.2构建时,会抛出错误error: macro "strncmp" requires 3 arguments, but only 2 given.使用arm-linux-gnueabihf-GCC 8.3.0构建似乎工作得很好.

显然,整个strncMP函数都可以放在宏中,它可以很好地工作,但理解为什么它不能编译将是非常有益的.

推荐答案

来自标准草案(N3096),7.1.4,库函数的使用

在头中声明的任何函数可以另外实现为在头中定义的类似函数的宏,因此如果库函数在包括其头时被显式声明,则可以使用下面所示的技术之一来确保声明不受这样的宏的影响.函数的任何宏定义都可以通过将函数的名称括在圆括号中来局部取消,因为该名称后面没有表示宏函数名展开的左括号.出于相同的语法原因,即使库函数也被定义为宏,也允许使用库函数的地址.1使用#undef删除任何宏定义也将确保引用实际的函数.

在您的例子中,strncmp在您的实现中既是一个函数又是一个宏,并且宏strncmp有3个参数.展开类似函数的宏时,参数的数量在展开之前根据宏定义确定并匹配,因此对于带有三个参数的宏strncmp,必须在宏参数列表中传递由两个逗号分隔的恰好三个参数,除非逗号括在括号中.如果strncmp是宏,则strncmp(str1, STRING_WITH_SIZE_MINUS_ONE("str2"))是语法错误.甚至在判断STRING_WITH_SIZE_MINUS_ONE的定义之前就产生了错误.

在较新的版本中,他们可能已经决定删除宏,因此这不再是问题.您总是可以通过在strncmp左右添加一对括号来隐藏宏版本,

将其更改为

(strncmp)(str1, STRING_WITH_SIZE_MINUS_ONE("str2"))

旁注:需要注意的是,你的宏只能处理已知大小的数组(编译时常量大小的数组,或VLA,但不包括未知大小的数组,如arr[]),其中字符串字面量是一种特殊情况.如果你传递一个const char*给你的宏,你的代码将编译,但在运行时有UB.您可以考虑使用strlen()来避免此问题.


1这意味着需要一个实现 for each 库函数提供一个实际的函数,即使它也为该函数提供了一个宏.

C++相关问答推荐

我可以动态分配具有空类型函数的矩阵吗?

为什么海湾合作委员会在共享对象中的. init_data的虚拟内存地址之前留出一个空白

gcc已编译的可执行文件TSB是否同时暗示最低有效字节和最低有效位?

标准的C17标准是用括号将参数包装在函数声明中吗

有没有可能我不能打印?(C,流程)

非常大的数组的大小

为什么我会收到释放后堆使用错误?

在另一个函数中使用realloc和指针指向指针

我的C函数起作用了,但我不确定为什么

Wcstok导致分段故障

CS50判断灯泡运动的问题,判断时多出一个灯泡,但不在终端上

不确定如何处理此编译错误

隐藏测试用例无法在c程序中计算位数.

在C中使用无符号整数模拟有符号整数

从整型转换为浮点型可能会改变其值.

赋值两侧的后置增量,字符指针

在我的函数中实现va_arg的问题

将char*数组深度复制到 struct 中?

If语句默认为true

Ubuntu编译:C中的文件格式无法识别错误