我正在看这个github logger project,并且在我自己的环境中尝试它。我试图将函数log_log
更改为static
,以便无法在其他文件中调用它,并且会强制“用户”(me)仅使用宏。
当我将函数更改为静态时,即使宏应该能够看到它,我也会在main中获得未定义的引用。为什么是这样?有没有办法做到这一点?
#include <stdio.h>
#include <stdarg.h>
#define LOG_VERSION "0.1.0"
typedef void (*log_LockFn)(void *udata, int lock);
enum { LOG_TRACE, LOG_DEBUG, LOG_INFO, LOG_WARN, LOG_ERROR, LOG_FATAL };
#define log_trace(...) log_log(LOG_TRACE, __FILE__, __LINE__, __VA_ARGS__)
#define log_debug(...) log_log(LOG_DEBUG, __FILE__, __LINE__, __VA_ARGS__)
#define log_info(...) log_log(LOG_INFO, __FILE__, __LINE__, __VA_ARGS__)
#define log_warn(...) log_log(LOG_WARN, __FILE__, __LINE__, __VA_ARGS__)
#define log_error(...) log_log(LOG_ERROR, __FILE__, __LINE__, __VA_ARGS__)
#define log_fatal(...) log_log(LOG_FATAL, __FILE__, __LINE__, __VA_ARGS__)
void log_set_udata(void *udata);
void log_set_lock(log_LockFn fn);
void log_set_fp(FILE *fp);
void log_set_level(int level);
void log_set_quiet(int enable);
void log_log(int level, const char *file, int line, const char *fmt, ...);
答案 0 :(得分:3)
由于未在标头中定义log_log
函数,因此出现“未定义引用”链接器错误;它只是声明。 (请参见Understanding the difference between definining and declaring a variable;这些概念在声明和定义函数时类似。)
说函数是static
,就是说log_log()
将在定义main()
函数的源文件中定义,并且还将分别定义在任何其他尝试调用它的文件中(除非该函数很简单,否则这将是浪费的)。但是定义不存在,因此在链接程序时会收到“ undefined reference”消息。使用默认的编译器选项,编译器(而不是链接程序)也会通知我,未定义声明为static
函数的函数。
如果不经过诸如包含包含log_log
函数的代码中定义main()
的源文件(不是标头,而是源文件)之类的扭曲,就无法做您尝试的操作。但是,您真的不想这样做;您真的,真的, 真的 不想这么做。
让懒惰保护您:输入log_log(CS_POTATOES, "codswallop", -366, "abuse is rampant")
比log_trace("abuse is rampant")
困难得多,因此人们不太可能这样做。而且,您始终可以搜索并替换直接致电log_log
的电话,对可能滥用此电话的团队成员提供适当的警告。
答案 1 :(得分:1)
预处理器不了解C。预处理器所做的全部工作是用对log_***
的调用替换log_log
宏的任何实例。只有在预处理器完成了这些替换之后,编译器才介入读取已被预处理器修改的代码。
编译器不在乎也不知道这些对log_log
的调用是由预处理程序进行的。它所看到的只是对您不应该使用的函数的引用,因为您已经声明了static
,因此它会发出错误。
答案 2 :(得分:1)
为什么宏不能使用静态函数
宏不使用 any 函数。它们只是扩展为源代码或其片段。以这种方式生成的源代码可以包含函数调用,但是它的语义完全相同,就好像它确实出现在文件中一样,而不是来自宏的扩展。
特别是,如果出现在给定文件中的宏扩展为包含函数调用的代码,则被调用函数必须是外部函数,或者其定义必须出现在与调用相同的源文件中。