Функциональный макрос и перечислитель с тем же именем

#c #macros #c-preprocessor

#c #макросы #c-препроцессор

Вопрос:

В следующем фрагменте у меня есть struct IndexError , который я возвращаю, когда пользователь допустил ошибку, используя мою библиотеку. У меня есть функциональный макрос, который приводит указатель на IndexError* и перечисление, оба вызываются INDEX_ERROR .

 enum errors {
    SUCCESS,
    INVALID_ARGUMENT,
    INDEX_ERROR
};

struct Error {
    char error_buff[BUFSIZ];
};

typedef struct Error Error;

struct IndexError {
    Error  parent;
    size_t invalid_index;
    // etc.
};

typedef struct IndexError IndexError;


#define INDEX_ERROR(obj) ((IndexError*) obj)
  

Примером того, как я бы использовал это, является:

 size_t pos = 4;
int IndexPointer* error = NULL;
int status = array_remove_item(my_array, pos, amp;error);
  

Затем я проверяю статус. Если он не возвращает SUCCESS , я бы проверил ошибку, потому что это должно указывать на вновь созданную ошибку.

Реализация одной из функций массива может выглядеть следующим образом:

 int array_remove_item(Array* array, size_t pos, Error** error_out)
{
    Error* error = NULL;
    if(pos >= array->size) {
        index_error_create(INDEX_ERROR(amp;error), pos); // use casting macro.
        *error_out = error;
        return INDEX_ERROR; // is this the macro or the value from the errors enum?
    }
    priv_array_remove_item(array, pos);
    return SUCCESS;
}
  

Итак, мой вопрос в том, return INDEX_ERROR; вернет ли INDEX_ERROR значение из перечисления, или препроцессор укусит меня, потому что мое именование неудобно?

Комментарии:

1. Замена макроса происходит на отдельном этапе, прежде чем другие идентификаторы будут переданы через компилятор. Эта ссылка на этап перевода могла бы быть полезной.

2. Макросы расширяются перед компиляцией. В результате ваше значение enum INDEX_ERROR будет заменено текстом макроса. Однако я ожидал бы, что препроцессор пожалуется, что вы ссылаетесь на макрос без параметра.

3. Напрямую не связаны, но идентификаторы _This _Sort зарезервированы для реализации для любого использования. Вы можете объявить typedef struct Error Error; просто отлично.

4. Также обратите внимание, что в C (а также C , но в будущем помечайте только язык, на котором вы на самом деле программируете, поскольку C и C в остальном являются двумя очень разными языками) символы, начинающиеся с подчеркивания и сопровождаемые заглавной буквой (например, _Error ), зарезервированы во всех областях для компилятора и стандартной библиотеки. Как правило, вам не следует определять такие символы самостоятельно.

5. @StoryTeller отредактировал и удалил подчеркивания

Ответ №1:

 return INDEX_ERROR; // is this the macro or the value from the errors enum?
  

Это перечислитель. Это не может быть результатом расширения функционального макроса, потому что за ним не следует сразу левый парный ( маркер, поскольку для препроцессора требуется1.

Правда, он немного вонючий. Разные имена для макроса и перечислителя сделают код более понятным и самоочевидным без необходимости читать спецификацию языка, напечатанную мелким шрифтом.



1n1570 6.10.3p10 «Каждый последующий экземпляр функциональноподобного имени макроса, за которым следует a (поскольку следующий токен предварительной обработки вводит последовательность токенов предварительной обработки, которая заменяется списком замены в определении»

Комментарии:

1. Эта ссылка не радует мой браузер, потому что соединение небезопасно.

2. @hetepeperfan — Серьезно? Я использую последнюю версию Chrome, и она отлично открывает ссылку (а chrome известен своей строгостью в отношении ссылок https).

3. Я использую Firefox, который поставляется с Ubuntu16.04, возможно, он немного устарел.

4. В любом случае, это идентификатор стандартного проекта, который я использовал (отредактированный в вопросе), и номер раздела. Вы можете проверить это из другого источника.