Подтвердить что ты не робот

Организация файлов C

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

Какие стратегии следует использовать для организации моего кода? Можно ли отделить "общедоступные" функции от "private" для конкретного файла?

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

4b9b3361

Ответ 1

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

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

То же самое относится к переменным, которые используются во многих модулях. Они должны войти в заголовочный файл, и там они должны быть отмечены ключевым словом "extern" . Примечание. Для функций ключевое слово "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();
    }

Ответ 2

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

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

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

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

Ответ 3

Несколько простых правил для запуска:

  • Поместите те объявления, которые вы хотите сделать "общедоступными" в заголовочном файле для создаваемого файла реализации C.
  • Только # включить заголовочные файлы в файле C, необходимые для реализации файла C.
  • включить заголовочные файлы в файл заголовка, только если это необходимо для объявлений в этом заголовочном файле.

  • Использовать метод защиты include, описанный Andrew OR, используйте #pragma once, если компилятор поддерживает его (что делает то же самое - иногда более эффективно).

Ответ 4

Compiler

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

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

Linker

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

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

Удачи!

-Adam

Ответ 5

Чтобы ответить на ваш дополнительный вопрос:

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

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

compiler --options tea.c

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

(Я замалчиваю некоторые подробности здесь. Существует много возможностей для изучения проектов C).

Ответ 6

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

Ответ 7

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

Данный программный продукт, как правило, включает в себя вывод из многих различных файлов .c. Как это обычно делается, так это то, что компилятор создает несколько объектных файлов (в unix-системах ".o" файлы, VC генерирует файлы .obj). Цель "компоновщика" состоит в том, чтобы компоновать эти объектные файлы в выходной файл (либо разделяемую библиотеку, либо исполняемый файл).

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

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

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

Ответ 8

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

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

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