Как вы определяете функции в заголовочных файлах?
Настройка
Если у меня есть такая программа
Заголовочный файл, который объявляет мою основную библиотечную функцию, primary()
и определяет короткую простую вспомогательную функцию, helper()
,
/* primary_header.h */
#ifndef _PRIMARY_HEADER_H
#define _PRIMARY_HEADER_H
#include <stdio.h>
/* Forward declare the primary workhorse function */
void primary();
/* Also define a helper function */
void helper()
{
printf("I'm a helper function and I helped!\n");
}
#endif /* _PRIMARY_HEADER_H */
Файл реализации для моей основной функции, которая его определяет.
/* primary_impl.c */
#include "primary_header.h"
#include <stdio.h>
/* Define the primary workhorse function */
void primary()
{
/* do the main work */
printf("I'm the primary function, I'm doin' work.\n");
/* also get some help from the helper function */
helper();
}
main()
файл, который проверяет код, вызывая primary()
/* main.c */
#include "primary_header.h"
int main()
{
/* just call the primary function */
primary();
}
Эта проблема
С помощью
gcc main.c primary_impl.c
не связывает, потому что primary_header.h
файл включается дважды, и поэтому существует недопустимое двойное определение функции helper()
, Как правильно структурировать исходный код для этого проекта, чтобы двойные определения не возникали?
3 ответа
Вы должны писать только прототип своей функции в заголовочном файле, тело вашей функции должно быть записано в файле.c.
Сделай это:
primary_header.c
/* primary_header.h */
#ifndef PRIMARY_HEADER_H
#define PRIMARY_HEADER_H
#include <stdio.h>
/* Forward declare the primary workhorse function */
void primary(void);
/* Also define a helper function */
void helper(void);
#endif /* PRIMARY_HEADER_H */
primary_impl.c
/* primary_impl.c */
#include "primary_header.h"
#include <stdio.h>
/* Define the primary workhorse function */
void primary()
{
/* do the main work */
printf("I'm the primary function, I'm doin' work.\n");
/* also get some help from the helper function */
helper();
}
void helper()
{
printf("I'm a helper function and I helped!\n");
}
Изменить: изменить _PRIMARY_HEADER_H
в PRIMARY_HEADER_H
, Как сказали @Jonathan Leffler и @Pablo, имена подчеркивания являются зарезервированными идентификаторами.
Вы почти никогда не пишете функцию внутри заголовочного файла, если она не помечена как всегда встроенная. Вместо этого вы пишете функцию в .c
файл и скопируйте объявление функции (не определение) в файл заголовка, чтобы его можно было использовать в другом месте.
Вы можете определить функцию в файлах заголовков, если она слабая, например:
// test.h
__attribute__((weak)) int test() {
static int s = 0;
return s++;
}
// a.c
#include "test.h"
#include <stdio.h>
void a(){
print("%d", test());
}
// b.c
#include "test.h"
#include <stdio.h>
void b(){
print("%d", test());
}
// main.c
#include "test.h"
#include <stdio.h>
void a();
void b();
void main(){
a();
b();
print("%d", test());
}
cc a.c b.c main.c
не вызовет ошибку нескольких определений, и вывод должен быть
012
как и ожидалось, что означает
a.c
,
b.c
а также
main.c
разделять то же самое
test
функция. Вы можете добиться того же результата в C++, используя.
Более того, слабая связь также может использоваться при определении переменной, что позволяет вам определять и инициализировать глобальную переменную в файлах заголовков без исходных файлов (аналогично C++).
Примечание:
Слабые символы не упоминаются стандартами языка C или C++.
Так что будьте осторожны при использовании в c. Но в C++
inline
а также
inline static
являются переносимой формой C++ 11 и C++17.