Как вы определяете функции в заголовочных файлах?

Настройка

Если у меня есть такая программа

Заголовочный файл, который объявляет мою основную библиотечную функцию, 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.

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