Есть несколько неправильных представлений, которые у вас есть: Прежде всего концепция «вызова» макроса. Это невозможно, даже если макрос выглядит как функция, это не функция, а макросы фактически не обрабатываются компилятором. Вместо этого макросы являются частью отдельного языка, который обрабатывается preprocessor, который берет исходный файл и модифицирует его для генерации translation unit, который видит компилятор. (Для получения дополнительной информации о фазах разности «компиляции» см. Например, this reference.)
Препроцессор делает это, в основном делая замену поиска во входном исходном файле: когда он видит макрос «вызов», он просто заменяет это с «телом» макроса. Когда он видит директиву #include
, он предварительно обрабатывает файл, а затем помещает содержимое вместо директивы.
Так что в вашем коде, когда препроцессор видит макрос MESSAGE
, он буквально заменяется на "this is message!"
. Фактический компилятор вообще не видит MESSAGE
, он видит только строковый литерал.
Другим заблуждением является то, как вы используете #include
директиву. Вы не должны использовать его, чтобы включить источник файлов. Вместо этого вы скомпилируете исходные файлы отдельно (что создает объектные файлы), а затем link сгенерированные файлы объектов вместе с любыми библиотеками, необходимыми для формирования окончательного исполняемого файла.
Чтобы решить проблему с макросами (и другими объявлениями), доступными для всех исходных файлов, вы используете файлы заголовков. Они похожи на исходные файлы, но содержат только объявления и макросы. Затем вы включаете заголовочный файл в оба исходных файла, и оба исходных файла будут знать о объявлениях и макросах, доступных в файле заголовка.
Итак, в вашем случае у вас должно быть три файла: основной исходный файл, исходный файл, содержащий эту функцию, и заголовочный файл, содержащий макрос и объявление функции (также известный как прототип). Что-то вроде
Файл заголовка, например. header.h
:
// First an include guard (see e.g. https://en.wikipedia.org/wiki/Include_guard)
#ifndef HEADER_H
#define HEADER_H
// Define the macro, if it needs to be used by all source files
// including this header file
#define MESSAGE "this is message!"
// Declare a function prototype so it can be used from other
// source files
void helloworld();
#endif
Основной исходный файл, например. main.c
:
// Include a system header file, to be able to use the `printf` function
#include <stdio.h>
// Include the header file containing common macros and declarations
#include "header.h"
int main(void)
{
// Use the macro
printf("From main, MESSAGE = %s\n", MESSAGE);
// Call the function from the other file
helloworld();
}
Другой файл, например hello.c
:
// Include a system header file, to be able to use the `printf` function
#include <stdio.h>
// Include the header file containing common macros and declarations
#include "header.h"
void helloworld(void)
{
printf("Hello world!\n");
printf("From helloworld, MESSAGE = %s\n", MESSAGE);
}
Теперь, если вы используете компилятор командной строки, как gcc
или clang
, то вы можете просто построить все это, делая, например,
$ gcc -Wall main.c hello.c -o myhello
Эта команда будет принимать два исходные файлы, main.c
и hello.c
и запустить препроцессор и компилятор на них для создания (временных) файлов объектов. Эти объектные файлы затем связаны вместе со стандартной библиотекой C для формирования программы myhello
(это то, что делает опция -o
, называет выходной файл).
Вы можете запустить myhello
:
$ ./myhello
From main, MESSAGE = this is message!
Hello world!
From helloworld, MESSAGE = this is message!
'#include" file2.c "' неверен. Всегда лучше включать '# define' в '.h' файлы. –
Вы имеете в виду 'void helloworld() {'? –