Home > Software engineering >  define anonymous enum with x-macros produces compilation error
define anonymous enum with x-macros produces compilation error

Time:11-28

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:

  1. The definition of the list's elements.
  2. 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 named X) with the elements' data. Each expansion of LIST is preceded by a definition of X with the syntax for a list element. The invocation of LIST expands X 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

  • Related