You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用X宏定义匿名枚举遇编译错误及errno字符串化方案咨询

问题:X宏实现errno字符串化时的编译错误及替代方案

开发大型项目时,需要将自定义errno宏转换为字符串用于日志输出,尝试用X宏实现但出现编译错误,相关代码及错误信息如下:

初始代码

// project_errno.h
#define PROJECT_ERR_KEY_FAILURE                         12222
#define PROJECT_ERR_CIPHER_ZERO_PADDING                 12345
#define PROJECT_ERR_FAILED_TO_SETUP_ENC_KEY             14004

改造步骤及代码

  1. 编写X宏文件:
// project_errno.hx
PROJECT_ERR_FUNC(PROJECT_ERR_KEY_FAILURE)                         12222
PROJECT_ERR_FUNC(PROJECT_ERR_CIPHER_ZERO_PADDING)                 12345
PROJECT_ERR_FUNC(PROJECT_ERR_FAILED_TO_SETUP_ENC_KEY)             14004
  1. 转为匿名枚举:
// project_errno.h
enum {
#define PROJECT_ERR_FUNC(name, value) name=value,
#include "project_errno.hx"
#undef PROJECT_ERR_FUNC
};
  1. 添加日志用字符串化函数:
// logging.h(声明)及logging.c(定义)
const char* stringify_errno(int errno) {
    switch (errno) {
#define PROJECT_ERR_FUNC(name, value) case name: return #value ;
#include "project_errno.hx"
#undef PROJECT_ERR_FUNC
    }
}

编译错误信息

project_errno.h:8:53: error: expected identifier before numeric constant
#define PROJECT_ERR_CIPHER_ZERO_PADDING                 12345
                                                        ^
..../project_errno.h:17:30: note: in definition of macro ‘PROJECT_ERR_FUNC’
#define PROJECT_ERR_FUNC(name, value) name=value,
                                      ^~~~
..../project_errno.hx:47:14: note: in expansion of macro ‘PROJECT_ERR_CIPHER_ZERO_PADDING ’PROJECT_ERR_FUNC(PROJECT_ERR_CIPHER_ZERO_PADDING,       12345)

project_errno.h:8:53: error: expected ‘}’ before numeric constant 
#define PROJECT_ERR_CIPHER_ZERO_PADDING                 12345
                                                        ^
..../project_errno.h:17:30: note: in definition of macro ‘PROJECT_ERR_FUNC’
#define PROJECT_ERR_FUNC(name, value) name=value,
                                      ^~~~
..../project_errno.hx:47:14: note: in expansion of macro ‘PROJECT_ERR_CIPHER_ZERO_PADDING ’PROJECT_ERR_FUNC(PROJECT_ERR_CIPHER_ZERO_PADDING,       12345)

project_errno.h:8:53: error: expected unqualified-id before numeric constant 
#define PROJECT_ERR_CIPHER_ZERO_PADDING                 12345
                                                        ^
..../project_errno.h:17:30: note: in definition of macro ‘PROJECT_ERR_FUNC’
#define PROJECT_ERR_FUNC(name, value) name=value,
                                      ^~~~
..../project_errno.hx:47:14: note: in expansion of macro ‘PROJECT_ERR_CIPHER_ZERO_PADDING ’PROJECT_ERR_FUNC(PROJECT_ERR_CIPHER_ZERO_PADDING,       12345)
                  ^~~~~~~~~~~~~~~~~~~~~~~
In file included from ......../project_errno.h:20:1: error: expected declaration before ‘}’ token
};
^

..../project_errno.h:17:30: note: in definition of macro ‘PROJECT_ERR_FUNC’
#define PROJECT_ERR_FUNC(name, value) name=value,
                                      ^~~~
..../project_errno.hx:47:14: note: in expansion of macro ‘PROJECT_ERR_CIPHER_ZERO_PADDING ’PROJECT_ERR_FUNC(PROJECT_ERR_CIPHER_ZERO_PADDING,       12345)
                  ^~~~~~~~~~~~~~~~~~~~~~~

错误原因分析

  1. X宏参数格式错误:project_errno.hx中X宏调用未将名称和值作为两个参数传入,正确写法应为PROJECT_ERR_FUNC(name, value),原写法会导致预处理器解析出非法语法。
  2. 宏定义冲突:原project_errno.h中保留了#define宏定义,预处理器会先展开PROJECT_ERR_CIPHER_ZERO_PADDING为12345,导致枚举中出现12345=12345,的非法代码——枚举成员必须是标识符,不能是数字。
  3. 参数名冲突:字符串化函数使用errno作为参数名,而errno是系统标准宏,会引发预处理器展开错误,需改用其他名称如err。
  4. 缺少default分支:switch语句无default分支,无法处理未知错误码,还会触发编译器警告。

修复后的X宏实现代码

1. 修正project_errno.h

删除原有宏定义,仅保留枚举生成逻辑:

// project_errno.h
#ifndef PROJECT_ERRNO_H
#define PROJECT_ERRNO_H

enum {
#define PROJECT_ERR_FUNC(name, value) name = value,
#include "project_errno.hx"
#undef PROJECT_ERR_FUNC
};

#endif // PROJECT_ERRNO_H

2. 修正project_errno.hx参数格式

// project_errno.hx
PROJECT_ERR_FUNC(PROJECT_ERR_KEY_FAILURE, 12222)
PROJECT_ERR_FUNC(PROJECT_ERR_CIPHER_ZERO_PADDING, 12345)
PROJECT_ERR_FUNC(PROJECT_ERR_FAILED_TO_SETUP_ENC_KEY, 14004)

3. 修正字符串化函数

// logging.c
#include "project_errno.h"

const char* stringify_errno(int err) {
    switch (err) {
#define PROJECT_ERR_FUNC(name, value) case name: return #name;
#include "project_errno.hx"
#undef PROJECT_ERR_FUNC
    default: return "UNKNOWN_PROJECT_ERROR";
    }
}

替代方案:数组映射实现

若觉得X宏的预处理器语法过于繁琐,可采用静态数组映射方案,仅需维护一处错误码与字符串的对应关系:

// project_errno.h
#ifndef PROJECT_ERRNO_H
#define PROJECT_ERRNO_H

typedef enum {
    PROJECT_ERR_KEY_FAILURE = 12222,
    PROJECT_ERR_CIPHER_ZERO_PADDING = 12345,
    PROJECT_ERR_FAILED_TO_SETUP_ENC_KEY = 14004,
    PROJECT_ERR_MAX // 标记数组大小
} ProjectErrno;

#endif // PROJECT_ERRNO_H
// logging.c
#include "project_errno.h"

typedef struct {
    ProjectErrno code;
    const char* msg;
} ErrMapping;

static const ErrMapping err_map[] = {
    {PROJECT_ERR_KEY_FAILURE, "PROJECT_ERR_KEY_FAILURE"},
    {PROJECT_ERR_CIPHER_ZERO_PADDING, "PROJECT_ERR_CIPHER_ZERO_PADDING"},
    {PROJECT_ERR_FAILED_TO_SETUP_ENC_KEY, "PROJECT_ERR_FAILED_TO_SETUP_ENC_KEY"}
};

const char* stringify_errno(int err) {
    for (size_t i = 0; i < sizeof(err_map)/sizeof(err_map[0]); i++) {
        if (err_map[i].code == err) {
            return err_map[i].msg;
        }
    }
    return "UNKNOWN_PROJECT_ERROR";
}

该方案可读性更强,调试更直观,适合对预处理器语法不熟悉的场景。

内容的提问来源于stack exchange,提问作者danwgh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 00:25:22