最近,我正在努力获取和设置 uci 文件上的某些字段。为了正确地获取失败原因,我决定使用一些宏,如下所示:
#define HANDLE_UCI_ERR(_cond_, _fmt_, ...) \
do { \
if (_cond_) { \
char *err_msg = NULL; \
uci_get_errorstr(g_uci_ctx, &err_msg, _fmt_); \
ERR(err_msg, ##__VA_ARGS__); \
free(err_msg); \
goto bail; \
} \
} while (0)
注意,这与问题无关,但为了编译 uci 代码,我使用here给出的步骤安装了它的库。
但是,它给了我以下编译错误:
gcc trial.c -luci -o trial
trial.c: In function ‘main’:
trial.c:37:11: error: expected ‘)’ before ‘err_msg’
37 | MY_ERR(err_msg, ##__VA_ARGS__); \
| ^~~~~~~
trial.c:14:38: note: in definition of macro ‘MY_PRINT’
14 | printf("[DM] " prefix " [%s:%d]: " fmt "\n", __FILE__, __LINE__, ##arg); \
| ^~~
trial.c:37:4: note: in expansion of macro ‘MY_ERR’
37 | MY_ERR(err_msg, ##__VA_ARGS__); \
| ^~~~~~
trial.c:72:2: note: in expansion of macro ‘HANDLE_UCI_ERR’
72 | HANDLE_UCI_ERR(rc != UCI_OK, "Not able to load package %s", PACKAGE_STR);
| ^~~~~~~~~~~~~~
trial.c:14:10: warning: format ‘%s’ expects a matching ‘char *’ argument [-Wformat=]
14 | printf("[DM] " prefix " [%s:%d]: " fmt "\n", __FILE__, __LINE__, ##arg); \
| ^~~~~~~
trial.c:19:3: note: in expansion of macro ‘MY_PRINT’
19 | MY_PRINT("Error : ", fmt, ##arg)
| ^~~~~~~~
trial.c:37:4: note: in expansion of macro ‘MY_ERR’
37 | MY_ERR(err_msg, ##__VA_ARGS__); \
| ^~~~~~
trial.c:72:2: note: in expansion of macro ‘HANDLE_UCI_ERR’
72 | HANDLE_UCI_ERR(rc != UCI_OK, "Not able to load package %s", PACKAGE_STR);
| ^~~~~~~~~~~~~~
trial.c:14:29: note: format string is defined here
14 | printf("[DM] " prefix " [%s:%d]: " fmt "\n", __FILE__, __LINE__, ##arg); \
| ~^
| |
| char *
trial.c:14:10: warning: format ‘%d’ expects a matching ‘int’ argument [-Wformat=]
14 | printf("[DM] " prefix " [%s:%d]: " fmt "\n", __FILE__, __LINE__, ##arg); \
| ^~~~~~~
trial.c:19:3: note: in expansion of macro ‘MY_PRINT’
19 | MY_PRINT("Error : ", fmt, ##arg)
| ^~~~~~~~
trial.c:37:4: note: in expansion of macro ‘MY_ERR’
37 | MY_ERR(err_msg, ##__VA_ARGS__); \
| ^~~~~~
trial.c:72:2: note: in expansion of macro ‘HANDLE_UCI_ERR’
72 | HANDLE_UCI_ERR(rc != UCI_OK, "Not able to load package %s", PACKAGE_STR);
| ^~~~~~~~~~~~~~
trial.c:14:32: note: format string is defined here
14 | printf("[DM] " prefix " [%s:%d]: " fmt "\n", __FILE__, __LINE__, ##arg); \
| ~^
| |
| int
Compilation exited abnormally with code 1
说实话,我不确定代码中的问题是什么。因此,我想分享它的可复制版本。这是简化版本:
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
#include <uci.h>
#define DEBUG_ERROR_LEVEL 2
int loglevel = 7;
#define MY_PRINT(prefix, fmt, arg...) do { \
printf("[DM] " prefix " [%s:%d]: " fmt "\n", __FILE__, __LINE__, ##arg); \
} while (0)
#define MY_ERR(fmt, arg...) \
if (loglevel > DEBUG_ERROR_LEVEL) \
MY_PRINT("Error : " fmt, ##arg)
#define HANDLE_UCI_ERR(_cond_, _fmt_, ...) \
do { \
if (_cond_) { \
char *err_msg = NULL; \
uci_get_errorstr(g_uci_ctx, &err_msg, _fmt_); \
MY_ERR(err_msg, ##__VA_ARGS__); \
free(err_msg); \
goto bail; \
} \
} while (0)
static const char *PACKAGE_STR = "package";
static struct uci_context *g_uci_ctx;
__attribute__((constructor))
void init_uci_context() {
g_uci_ctx = uci_alloc_context();
if (!g_uci_ctx) {
exit(EXIT_FAILURE);
}
if (uci_set_confdir(g_uci_ctx, "/home/[email protected]/tmp/config/") != 0) {
exit(EXIT_FAILURE);
}
}
__attribute__((destructor))
void cleanup_uci_context() {
if (g_uci_ctx) {
uci_free_context(g_uci_ctx);
}
}
int main() {
int rc = 0;
struct uci_package *pkg = NULL;
rc = uci_load(g_uci_ctx, PACKAGE_STR, &pkg);
HANDLE_UCI_ERR(rc != UCI_OK, "Not able to load package %s", PACKAGE_STR);
bail:
uci_unload(g_uci_ctx, pkg);
return rc;
}
要解决这个问题,我可以更新
HANDLE_UCI_ERR
宏,如下所示:
#define HANDLE_UCI_ERR(cond, fmt, arg...) \
do { \
if (cond) { \
char *err_msg = NULL; \
uci_get_errorstr(g_uci_ctx, &err_msg, NULL); \
MY_ERR("%s : " fmt, err_msg, ##arg); \
free(err_msg); \
goto bail; \
} \
} while (0)
如果有人能告诉我我错过了什么,我真的很感激。
亲切的问候。
这个...
MY_PRINT("Error : " fmt, ##arg)
当 MY_ERR
是或扩展为标识符(例如
fmt
)时,... 来自
err_msg
宏的扩展为无效 C 代码。您似乎正在尝试执行字符串连接,但这仅适用于字符串文字,并且 err_msg
不是字符串文字。
您提出的解决方案或类似的解决方案是最简单的解决方案,但如果您决定使用可变参数宏,那么您可能应该使用它们的标准形式,使用
__VA_ARGS__
而不是 GCC 风格的命名变量参数。