我正在尝试创建一个函数,通常用于确定文件/目录是否存在、是否在某个路径内以及是否属于指定类型(S_ISREG、S_ISDIR、...
以下是与该问题相关的部分来源:
int checkExists(const char *name, void *func(int))) {
struct stat st ;
int returnValue = DOES_NOT_EXIST ;
BOOL isInSourceHierarchy, isInTargetHierarchy ;
if (stat(name, &st) != -1) {
returnValue = EXISTS ;
if (memcmp(name, top_dir, strlen(top_dir)))
returnValue |= IN_SOURCE_STRUCTURE ;
if (memcmp(name, tgt_dir, strlen(tgt_dir)))
returnValue |= IN_TARGET_STRUCTURE ;
if (func != NULL) {
if (objType == func(st.st_mode))
returnValue |= RIGHT_TYPE ;
}
}
return returnValue ;
}
. . .
if (S_ISREG(0)) {} // Yes, I know, I know. This is for demonstration only.
if (checkExists(old, S_ISREG)) {
// Do something
} else { // Old file doesn't exist
// Do something else
}
当我尝试编译它时,我得到:
linkStructure.c:642:31: error: ‘S_ISREG’ undeclared (first use in this function)
642 | if (checkExists(old, S_ISREG)) {
| ^~~~~~~
可以看出,当然,对于按设计使用的宏没有任何抱怨。所以我的问题是:有没有办法让我像这样在源代码中引用宏?或者我只能在函数中模拟宏?(我想我可以传递预期的类型而不是函数,但为了清楚起见,我想了解这个限制。)
它说
S_ISREG
未定义,因为预处理器不会忽略括号。#define FOO()
定义FOO()
,而不是FOO
。此外,您的函数需要一个函数指针作为参数,但是宏是编译时唯一的符号,您不能获取其地址。
但你可以将它包装在一个函数中:
现在你可以按照你想要的方式使用它了:
并且可以保留原有代码的灵活性。
不,没有额外的步骤你就无法完成你想要实现的目标。
S_ISREG
不存在,并且无法预知其S_ISREG(x)
会扩展成什么样。请记住,宏只是执行标记替换,这意味着
S_ISREG(x)
在解析开始之前(理论上)就会用不同的代码替换。假设它扩展为类似的东西((x) & S_IFREG)
。你如何将它传递给你的函数?你必须从中创建一个函数。或者,您可以传递
S_IFREG
(扩展为掩码)并自己执行适当的位操作。但是,第二种方法的灵活性较差。第一种方法可以使用更复杂的检查。
但是你不能用第二种方法来实现这一点。
该
S_ISREG
宏是一个类似函数的宏,因此简单地使用它来说S_ISREG
是无效的。您需要传入相关模式的标志,即
S_IFREG
使用该标志和文件模式执行位掩码。