来自标准草案(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 库函数提供一个实际的函数,即使它也为该函数提供了一个宏.