Im working on a big project and I have a lot of errno macros.
I want to write a helper functions for the logger that stringify each of these errno to a string. i decided to use x-macros but Im getting compilation errors
in the first place the code was like this:
// 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
the way i sort it out is as the following:
- In a different file i places the x-macros:
// 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
- then I turned it into an enum:
// project_errno.h
enum {
#define PROJECT_ERR_FUNC(name, value) name=value,
#include "project_errno.hx"
#undef PROJECT_ERR_FUNC
};
- then i added a function that will be used by the logger:
// logging.h (declaration) and (definition) 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
}
}
So, looks pretty good, but i can't get it to compile, Im getting the following compilation errros:
project_errno.h:8:53: error: 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: 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)
^~~~~~~~~~~~~~~~~~~~~~~
I can't understand why im getting those errors (im getting the same error message multiple time in the same compilation session), and i hope you guys could help me. Also, if you have any other solution to solve the problem i intended to solve in the first place (using the errno macros and add a functions to stringify those errnos whenever Im adding an errno to the project [in only one place]), i'd love to hear about it Thanks
CodePudding user response:
Edited answer:
I was able to generate the enum using
enum {
#define PROJECT_ERR_FUNC(name) , name =
PROJECT_ERR_START_OF_ENUM = -1
#include "project_errno.hx"
#undef PROJECT_ERR_FUNC
};
but had to remove the backtick at the end of project_errno.hx
. The above code will only work if you do not include project_errno.h
before.
A complete minimum working program would be
enum {
#define PROJECT_ERR_FUNC(name) , name =
PROJECT_ERR_START_OF_ENUM = -1
#include "project_errno.hx"
#undef PROJECT_ERR_FUNC
};
#include <iostream>
int main() {
std::cout << PROJECT_ERR_KEY_FAILURE << std::endl;
return 0;
}
that will print 12222
.
CodePudding user response:
I'd follow the recipe shown in the Wikipedia page about X Macros:
Implementation
An X macro application consists of two parts:
- The definition of the list's elements.
- Expansion(s) of the list to generate fragments of declarations or statements.
The list is defined by a macro or header file (named,
LIST
) which generates no code by itself, but merely consists of a sequence of invocations of a macro (classically namedX
) with the elements' data. Each expansion ofLIST
is preceded by a definition ofX
with the syntax for a list element. The invocation ofLIST
expandsX
for each element in the list.
In particular the second example, the one with X macro as argument
Pass name of the worker macro into the list macro. This both avoids defining an obscurely named macro (
X
), and alleviates the need to undefine it.
Which, in OP's use case, leads to the following three files:
// project_errno.h
#ifndef PROJECT_ERRNO_H
#define PROJECT_ERRNO_H
#define FOR_EACH_ERR_ID_VALUE_PAIR(DO) \
DO(PROJECT_ERR_KEY_FAILURE, 12222) \
DO(PROJECT_ERR_CIPHER_ZERO_PADDING, 12345) \
DO(PROJECT_ERR_FAILED_TO_SETUP_ENC_KEY, 14004)
#define DEFINE_ENUM_ITEM(err, value) err = value,
enum project_errs {
FOR_EACH_ERR_ID_VALUE_PAIR( DEFINE_ENUM_ITEM )
};
#undef DEFINE_ENUM_ITEM
#endif
// logging.h
#ifndef LOGGING_H
#define LOGGING_H
const char* stringify_errno(int errno);
#endif
// logging.c
#include <stdio.h>
#include "project_errno.h"
#define STRINGIFY_ERR_VALUE_NAME(name, value) case name: \
return "[" #value "] " #name;
const char* stringify_errno(int errno)
{
switch (errno) {
FOR_EACH_ERR_ID_VALUE_PAIR(STRINGIFY_ERR_VALUE_NAME)
default:
return "[-----] UNKWOWN";
}
}
#undef STRINGIFY_ERR_VALUE_NAME
Testable here: https://wandbox.org/permlink/aNJCI7lQihkFnYzp