Макросы на C, которые генерируют разный код при первом и последующих вызовах

Как мне определить макрос в C, чтобы я мог использовать ключевое слово «extern» при первом проходе в файле заголовка, а затем при последующих проходах инициализировать постоянные переменные? Я использую Visual Studio 2022 на компьютере с Windows 10.

На данный момент у меня есть что-то вроде следующего в моем заголовочном файле "images.h"

#pragma once

#include <stdio.h>
// Other #includes

typedef const unsigned char CBYTE;
typedef const int CINT;
// Other typedefs

#include "globals.h"
// Rest of the "images.h" header file.

Затем в моем файле "globals.h" у меня есть следующий код:

#ifndef _GLOBALS_H_
#define _GLOBALS_H_

extern CBYTE gc_eod16;
extern CINT gc_stf;

#else

CBYTE gc_eod16 = 127;
CINT gc_stf = 2;

#endif

Тогда в файле "images.c" с основной функцией у меня примерно так:

#include "images.h"
#include "globals.h"

int main(void) {

    // Code in main

    return 0;
}

Поскольку у меня есть несколько исходных файлов, которые скомпилированы вместе, мне нужно использовать ключевое слово «extern» и иметь #include «images.h» в верхней части других файлов.

Вместо того, чтобы инициализировать глобальные константы отдельно в файле с помощью основной функции, я хотел поместить их с помощью «extern» и инициализировать их в файле «globals.h». Кажется, компилируется нормально, но повторять глобальные константы в файле «globals.h» неаккуратно.

Мой вопрос в том, есть ли макрос, чтобы при первом включении "globals.h" операторы:

extern CBYTE gc_eod16;
extern CINT gc_stf;

генерируются, то при следующем #include они заменяются на:

CBYTE gc_eod16 = 127;
CINT gc_stf = 2;

так что в исходниках на каждую переменную приходится по одной строке, т.е. на первом #include "extern" ставится перед типом и именем переменной, затем на втором #include "extern" опускается, а после переменной идет строка "= 127; и т.д. дописывается?

Как это делается? Буду очень благодарен узнать.

Вы не можете создать макрос, который будет работать по-разному при каждом проходе, но вы можете удалить макрос и определить его по-другому. Смотрите #undef.

Mark Ransom 23.04.2022 05:40

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

user3386109 23.04.2022 05:59

@user3386109 — за очень немногими исключениями, например <assert.h>

Jonathan Leffler 23.04.2022 06:24

Вы можете найти обсуждение альтернативных способов сделать это в Как использовать extern для обмена переменными между исходными файлами?, особенно ближе к концу (довольно длинного ответа).

Jonathan Leffler 23.04.2022 06:26
3 метода стилизации элементов HTML
3 метода стилизации элементов HTML
Когда дело доходит до применения какого-либо стиля к нашему HTML, существует три подхода: встроенный, внутренний и внешний. Предпочтительным обычно...
Формы c голосовым вводом в React с помощью Speechly
Формы c голосовым вводом в React с помощью Speechly
Пытались ли вы когда-нибудь заполнить веб-форму в области электронной коммерции, которая требует много кликов и выбора? Вас попросят заполнить дату,...
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Будучи разработчиком веб-приложений, легко впасть в заблуждение, считая, что приложение без JavaScript не имеет права на жизнь. Нам становится удобно...
Flatpickr: простой модуль календаря для вашего приложения на React
Flatpickr: простой модуль календаря для вашего приложения на React
Если вы ищете пакет для быстрой интеграции календаря с выбором даты в ваше приложения, то библиотека Flatpickr отлично справится с этой задачей....
В чем разница между Promise и Observable?
В чем разница между Promise и Observable?
Разберитесь в этом вопросе, и вы значительно повысите уровень своей компетенции.
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Клиент для URL-адресов, cURL, позволяет взаимодействовать с множеством различных серверов по множеству различных протоколов с синтаксисом URL.
1
4
44
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Нет.

Вы хотите, чтобы препроцессор запоминал информацию между единицами компиляции. Чем нельзя.

Просто будьте хорошим соседом и инициализируйте переменные в их собственном .cpp файле.

Теперь, если вы все еще хотите делать что-то сложным путем, вы можете сделать что-то похожее на то, что делается в Windows при компиляции и использовании DLL.

// globals.h

#ifndef BUILDING_GLOBALS
  extern CBYTE gc_eod16;
  extern CINT gc_stf;
#else
  CBYTE gc_eod16 = 127;
  CINT gc_stf = 2;
#endif

Затем вам нужно будет изменить только один файл .cpp, чтобы он выглядел следующим образом:

#define BUILDING_GLOBALS
#include "globals.h"

Он ведет себя следующим образом:

  • Каждый файл, который не определяет BUILDING_GLOBALS, увидит extern.
  • Только один файл будет определять BUILDING_GLOBALS, и этот файл увидит инициализацию.

ОК, большое спасибо JuanR, все работает без ошибок. Я только что заменил #ifndef GLOBALS_H и #define GLOBALS_H в верхней части "globals.h" на #ifndef BUILDING_GLOBALS. В основном заголовочном файле «images.h» у меня все еще есть #include «globals.h», и я добавил #define BUILDING_GLOBALS перед #include «globals.h» в «images.c», который содержит основную функцию и определяет глобальные переменные. . Все файлы "*.c" имеют #include "images.h" вверху, поэтому все они знают о глобальной переменной. Ссылка Джонатана Леффлера о том, как использовать «extern», также очень полезна.

csharp 23.04.2022 20:59

здорово! пожалуйста, отметьте ответ как принятый для завершения.

JuanR 24.04.2022 01:43

Другие вопросы по теме