как я могу принудительно реализовать определение исходного файла для файла заголовка

#c #gcc

#c #gcc

Вопрос:

ниже приведен код:

 //test.h
...
extern int globalVariable;
...
  
 //test.c

#include "test.h"
...
int globalVariable = 2020;
...
  
 //main.c

#include <stdio.h>
#include "test.h" 

int main()
{
   printf("Value is %d", globalVariable);
}
  

допустим, в сценарии объявлены сотни переменных, test.h и globalVariable это всего лишь одна из них.

поскольку существует множество переменных, я легко допускаю ошибку опечатки в test.c как:

 #include "test.h"

int globalVariables = 2020;   //extra 's' in the name which contradicts the declaration of its counterpart in test.h
  

если я скомпилирую (только скомпилирую, не связывая их) test.c , test.h и main.c , он скомпилируется и не покажет ошибки. неразрешенная ошибка возникнет только тогда, когда компоновщик задействован на этапе компоновки.

Но в большом приложении я мог бы просто написать некоторые модули без необходимости связывать все существующие с исполняемым файлом, поэтому было бы лучше, если бы компилятор выдавал ошибку на этапе компиляции, чтобы указать ошибку, чтобы я мог исправить их как можно скорее, так как я могу позволить компилятору принудительно реализовать определение исходного файла для файла заголовка?

Ответ №1:

Вы также могли бы использовать препроцессор

test.h:

 #ifndef TEST_C_IMPLEMENTATION
#define DEFINE_AND_INIT_VARIABLE(type, name, value) 
    extern type name;
#else
#define DEFINE_AND_INIT_VARIABLE(type, name, value) 
    type name = value;
#endif

DEFINE_AND_INIT_VARIABLE(int, globalVariable, 2020);
  

test.c:

 #define TEST_C_IMPLEMENTATION
#include "test.h"
  

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

Ответ №2:

В объявлении extern int globalVariable; говорится, что переменная существует где-то, но не обязательно в текущей единице перевода. Таким образом, любой исходный файл, который включает заголовок, содержащий это объявление, будет знать, что переменная существует, не требуя полного определения.

Затем, когда вы перейдете к этапу компоновки, вы получите сообщение об ошибке, касающееся glovalVariable того, что оно не определено. Поскольку переменные объявлены в test.h, по соглашению определение должно быть в test.c. После проверки этого файла вы бы обнаружили, что такой переменной не существует, и могли бы затем либо добавить ее, либо найти опечатку и исправить ее.

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

1. @dbusg таким образом, я не буду предупрежден об опечатке, пока не создам компоновку файлов?

2. @dbush прав. Ваш вопрос касается реализации соглашения о кодировании. Если вы хотите, вы можете реализовать эту проверку в виде сценария и выполнить его как часть вашего makefile (или процесса сборки). Например: Скрипт, который извлекает список объявлений extern из файлов .h и определения extern из файлов .c и находит записи в списке .h, которых нет в списке .c. Имейте в виду, что вам, возможно, придется реализовать мини-анализатор C для обработки объявлений extern и определений переменных. Если вы действительно собираетесь пойти по этому пути, попробуйте ANTLR, который может сгенерировать анализатор на основе грамматики C.