Если вы пишете только тривиальные приложения с небольшим количеством функций, на самом деле нет необходимости объединять все в логические группы процедур. Однако, если у вас есть необходимость в разработке большой системы, вам необходимо уделить внимание тому, где определить каждую из ваших функций.

вык делать все свое кодирование в одном C-файле. Тем не менее, я работаю над проектом, достаточно большим, чтобы это стало непрактичным. Я включал их вместе, но сталкивался с случаями, когда несколько раз включал некоторые файлы и т. Д. Я слышал о файлах .h, но я не уверен, какова их функция (или почему иметь 2 файла лучше, чем 1).

Какие стратегии я должен использовать для организации своего кода? Можно ли отделить «публичные» функции от «приватных» для конкретного файла?

Этот вопрос ускорил мой запрос. В файле tea.h нет ссылки на файл tea.c. Знает ли компилятор, что каждый файл .h имеет соответствующий файл .c?

Ответы на вопрос(8)

составитель

Эта тема - Обратите внимание, что есть два файла - заголовок tea.h и код tea.c. Вы объявляете все общедоступные определения, переменные и прототипы функций, к которым другие программы должны обращаться в заголовке. В вашем основном проекте вы #include и этот код теперь может получить доступ к функциям и переменным чайного модуля, которые упомянуты в заголовке.

Это становится немного сложнее после этого. Если вы используете Visual Studio и многие другие IDE, которые управляют вашей сборкой, то игнорируйте эту часть - они позаботятся о компиляции и связывании объектов.

Linker

Когда вы компилируете два отдельных файла C, компилятор создает отдельные объектные файлы - так что main.c становится main.o, а tea.c становится tea.o. Работа компоновщика состоит в том, чтобы просмотреть все объектные файлы (ваши main.o и tea.o) и сопоставить ссылки - поэтому, когда вы вызываете функцию чая в main, компоновщик изменяет этот вызов, так что он действительно вызывает правильный функция в чае. Компоновщик создает исполняемый файл.

Существуетотличный учебник это углубляется в эту тему, включая сферу и другие проблемы, с которыми вы столкнетесь.

Удачи!

-Адам

Этот вопрос ускорил мой запрос. В файле tea.h нет ссылки на файл tea.c. Знает ли компилятор, что каждый файл .h имеет соответствующий файл .c?

Компилятор не касается в первую очередь заголовочных файлов. Каждый вызов компилятора компилирует исходный файл (.c) в файл объекта (.o). За кулисами (то есть вmake файл или файл проекта) создается командная строка, эквивалентная этой:

compiler --options tea.c

Исходный файл#includes все файлы заголовков для ресурсов, на которые он ссылается, так компилятор находит файлы заголовков.

(Я здесь приукрашиваю некоторые детали. Есть много, чтобы узнать о построении проектов C).

нкций. Это необходимо, чтобы вы могли включить нужные вам прототипы в ваш C-файл, не объявляя все нужные вам функции в одном файле.

Например, когда вы#include <stdio.h>, это обеспечивает прототипы для printf и других функций ввода-вывода. Символы для этих функций обычно загружаются компилятором по умолчанию. Вы можете посмотреть системные файлы .h в / usr / include, если вас интересуют обычные идиомы, связанные с этими файлами.

Если вы пишете только тривиальные приложения с небольшим количеством функций, на самом деле нет необходимости объединять все в логические группы процедур. Однако, если у вас есть необходимость в разработке большой системы, вам необходимо уделить внимание тому, где определить каждую из ваших функций.

чтобы каждый .c фокусировался на определенной области функциональности. Используйте соответствующий файл .h для объявления этих функций.

Каждый файл .h должен иметь защиту заголовка вокруг своего содержимого. Например:

#ifndef ACCOUNTS_H
#define ACCOUNTS_H
....
#endif

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

что вы на самом деле не сделали много серьезных разработок. Обычный случай - ваш код будет слишком большим, чтобы поместиться в один файл. Хорошее правило заключается в том, что вы должны разбивать функциональность на логические единицы (файлы .c), и каждый файл должен содержать не более того, что вы можете легко удерживать в своей голове за один раз.

Затем данный программный продукт обычно включает выходные данные из множества различных файлов .c. Обычно это делается так, что компилятор создает несколько объектных файлов (в системах Unix ".o" файлы VC генерируют файлы .obj). Назначение «компоновщика» состоит в том, чтобы скомпоновать эти объектные файлы в выходные данные (совместно используемую библиотеку или исполняемый файл).

Обычно ваши файлы реализации (.c) содержат фактический исполняемый код, в то время как заголовочные файлы (.h) имеют объявления открытых функций в этих файлах реализации. Вы можете довольно легко иметь больше заголовочных файлов, чем файлов реализации, и иногда заголовочные файлы также могут содержать встроенный код.

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

Я бы порекомендовал вам скачать и посмотреть исходный код ядра Linux. Это довольно масштабно для C-программы, но хорошо организовано в отдельные области функциональности.

Поместите те объявления, которые вы хотите сделать «общедоступными», в заголовочный файл для создаваемого вами файла реализации C.Только заголовочные файлы #include в C-файле, которые необходимы для реализации C-файла.включать заголовочные файлы в заголовочный файл, только если это требуется для объявлений в этом заголовочном файле.Используйте метод include guard, описанный Andrew ИЛИ use#pragma один раз если компилятор поддерживает это (что делает то же самое - иногда более эффективно)
 Andrew07 сент. 2008 г., 01:23
Это отличный момент. Файл заголовка (.h) должен включать только те функции, которые вы хотите сделать общедоступными. Все, что является частным для модуля компиляции (подробности реализации), не должно быть там; оставьте их в файле кода (.c).
 vonbrand01 февр. 2013 г., 23:11
Добавьте, что файл xxx.h должен быть включен в xxx.c, чтобы убедиться, что определения (xxx.c) и декларации (xxx.h) совпадают (разногласия могут привести к очень неприятным ошибкам). Если у вас есть материалы для широкой публики и другие для локального использования в соседних файлах, непременно создайте xxx.h и xxx-local.h.

приведенных выше, одно небольшое преимущество разделения вашего кода на модули (отдельные файлы) заключается в том, что если вам нужны глобальные переменные, вы можете ограничить их область действия одним модулем с помощью ключевого слова ' статическая. (Вы также можете применить это к функциям). Обратите внимание, что это использование «static» отличается от его использования внутри функции.

Решение Вопроса

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

Если вам нужна только функция в определенном файле .c (а не в любом другом модуле), объявите его область действия static. Это означает, что он может быть вызван только из файла c, в котором он определен.

То же самое касается переменных, которые используются в нескольких модулях. Они должны войти в заголовочный файл и там они должны быть помечены ключевым словом «extern». Примечание. Для функций ключевое слово extern необязательно. Функции всегда считаются «внешними».

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

Например:

Module1.c:

    #include "Module1.h"

    static void MyLocalFunction(void);
    static unsigned int MyLocalVariable;    
    unsigned int MyExternVariable;

    void MyExternFunction(void)
    {
        MyLocalVariable = 1u;       

        /* Do something */

        MyLocalFunction();
    }

    static void MyLocalFunction(void)
    {
      /* Do something */

      MyExternVariable = 2u;
    }

Module1.h:

    #ifndef __MODULE1.H
    #define __MODULE1.H

    extern unsigned int MyExternVariable;

    void MyExternFunction(void);      

    #endif

Module2.c

    #include "Module.1.h"

    static void MyLocalFunction(void);

    static void MyLocalFunction(void)
    {
      MyExternVariable = 1u;
      MyExternFunction();
    }

Ваш ответ на вопрос