Как переместить функции C в отдельный файл?

Я начинаю программировать на C. В настоящее время у меня есть большой файл, содержащий множество функций. Я бы хотел вынести эти функции в отдельный файл, чтобы код было легче читать. Однако я не могу понять, как правильно включить/скомпилировать, и не могу найти примера ни в одном онлайн-руководстве, которое я нашел. Вот упрощенный пример:

  #include  #include  void func1 (void) {printf ("Функция 1!  N");  } void func2 (void) {printf ("Функция 2!  n");} int main (void) {func1 ();  func2 ();  return 0;}  

Как перенести функции C в отдельный файл? К вашему сведению: я использую gcc.

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

  #include   #include  int counter = 0; void func1 (void) {printf ("Функция 1!  n");  счетчик ++;} int main (void) {func1 ();  return 0;}  

Перемещение этих функций во внешний файл не работает, потому что они должны ссылаться на эту глобальную переменную:

  #include  #include  #include "functions.c" int counter = 0; int main (void) {func1 ();  counter = 100;  return 0;}  

Как я могу обойти эту проблему?


32

Хорошо. Начнем.

Ваш файл main.c

  #include  #include   #include "functions.h" int main (void) {func1 ();  func2 ();  return 0;}  

Ваш файл functions.h

  void func1 (void)  ; void func2 (void);  

Ваш файл functions.c

  #include  "functions.h" void func1 (void) {printf ("Function 1!  n");} void func2 (void) {printf ("Function 2!  n");}  

Скомпилируйте его с помощью:

  gcc -o main.exe main.c functions.c  

Поделиться
отредактировано 13 апреля ’19 в 3:18
cyclaminist
1,45611 золотых знаков33 серебряных знака1212 бронзовых знаков
ответил 01 ноя 2013 в 18:37
  • Спасибо за полный пример. Кажется, что создание файла заголовка не нужно, если я могу просто #include "functions.c" . Зачем мне создавать файл заголовка? — Эндрю 01 нояб., В 18:44
  • 1
    Вы должны создать заголовок, потому что, как правило, у вас есть более одного исходного файла, использующего функции (так же, как и main.c , есть также aux.c и …), и все они не могут использовать трюк #include "func1.c" ; только один из исходных файлов может это сделать, но другие по-прежнему нуждаются в объявлениях функций, поэтому вам нужен заголовок. — Джонатан Леффлер, 01 ноя., 13:49
  • 1
    да. но хорошей практикой является включение файла заголовка, чтобы все ваши глобальные объявления шли туда, а ваш код выглядел хорошо. Мы также согласны с Джонатаном Леффлером. — Раджу Кунде 01 нояб., В 18:53
  • 1
    @ user1940987 Хорошая идея — включать файлы заголовков, но плохо, если файл заголовка включает исходный файл, поскольку это лишает смысла создание отдельного файла заголовка. — Дэвид М. Сыздек, 01 ноя. 2013, в 18:57
  • 1
    В вашем примере вы включаете прототипы функций после определений функций, что в большинстве случаев делает даже создание прототипа функции спорным. — Дэвид М. Сыздек 01 нояб., 13:18
| показать 1 дополнительный комментарий

Хорошо. Начнем.

Ваш файл main.c

  #include  #include   #include "functions.h" int main (void) {func1 ();  func2 ();  return 0;}  

Ваш файл functions.h

  void func1 (void)  ; void func2 (void);  

Ваш файл functions.c

  #include  "functions.h" void func1 (void) {printf ("Function 1!  n");} void func2 (void) {printf ("Function 2!  n");}  

Скомпилируйте его с помощью:

  gcc -o main.exe main.c functions.c  

10

Самый распространенный способ — разместить прототипы ваших функций в файле заголовка, а ваши реализации функций — в исходный файл. Например:

func1.h

  #ifndef MY_FUNC1_H # define MY_FUNC1_H # include //объявляет переменнуюextern int var1; //объявляет функциюvoid func1 (void); # endif  

func1.c

  #include "func1.h"//определяет переменную int var1 = 512;//определяет функциюvoid func1 (void) {printf ("Function 1!  n");}  

func2.h:

  #ifndef MY_FUNC2_H # define MY_FUNC2_H # include  void func2 (void); # endif  

func2.c:

  #include "func1. h "//включен для использования var1 # include" func2.h "void func2 (void) {printf (" Функция 2 с var1 ==% i  n ", var1);}  

main.c:

  #include  #include "func1.h" #include "func2.h" int main (void) {  var1 + = 512; func1 (); func2 (); return 0;}  

Затем вы должны компилировать, используя следующее:

  gcc -c -o func1.o func1.cgcc -c -o func2.o func2.cgcc -c -o main.o main.cgcc -o myprog main.o func1.o func2.o./myprog 

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

Как правило, вам нужен только файл заголовка один раз для этого предназначены макросы #ifndef #define #endif в файлы заголовков.

Поделиться
отредактировал 1 ноября 2013 в 19:15
ответил 01 ноя. ’13 в 18:49
  • Спасибо! Я добавил обновление, в котором упоминаются глобальные переменные. Как бы я с этим справился? — Эндрю 01 нояб., 19:09
  • Обратите внимание, что ни func1.h , ни func2.h не должны включать чтобы объявления в файле компилировались, поэтому вложенное включение следует исключить. Заголовки должны быть идемпотентными (как и ваш, из-за защиты заголовков) и самодостаточными. Ваши тоже самодостаточны, но содержат ненужные заголовки, что неоптимально. См. Следует ли использовать #include в заголовках? — Джонатан Леффлер 01 нояб., 20:26
  • @JonathanLeffler Хотя технически это верно, я обнаружил, что лучше включать файлы заголовков, необходимые для предварительной обработки нового заголовка, чем требовать, чтобы исходные файлы, вызывающие его, сделали это. Отличным примером этого может быть включение stdint.h для использования определенных типов ширины, таких как uint32_t и uint64_t. — Дэвид М. Сыздек 01 нояб., 21:05
  • Если функции в заголовке используют типы из , тогда вы должны включить в шапке. Ваши заголовки должны быть как самодостаточными, так и идемпотентными.. Это требование самодостаточности: вы должны иметь возможность использовать заголовок без необходимости включать что-либо еще. Идемпотентность достигается охранниками заголовка; включение заголовка дважды (намеренно или, чаще всего, случайно или случайно) не должно вызывать проблем. Подробности смотрите в сообщениях, на которые были ссылки ранее. — Джонатан Леффлер 01 нояб., 13:24
добавить комментарий |

Наиболее распространенный способ — поместить прототипы функций в файл заголовка, а реализации функций — в исходный файл. Например:

func1.h

  #ifndef MY_FUNC1_H # define MY_FUNC1_H # include //объявляет переменнуюextern int var1; //объявляет функциюvoid func1 (void); # endif  

func1.c

  #include "func1.h"//определяет переменную int var1 = 512;//определяет функциюvoid func1 (void) {printf ("Function 1!  n");}  

func2.h:

  #ifndef MY_FUNC2_H # define MY_FUNC2_H # include  void func2 (void); # endif  

func2.c:

  #include "func1.h"//включен для использования var1 # include "func2.h" void func2 (void) {printf ("Функция 2 с var1 ==  % i  n ", var1);}  

main.c:

  #include  #include  "func1.h" #include "func2.h" int main (void) {var1 + = 512;  func1 ();  func2 ();  return 0;}  

Затем вы должны скомпилировать, используя следующее:

  gcc -c -o func1.o func1.cgcc  -c -o func2.o func2.cgcc -c -o main.o main.cgcc -o myprog main.o func1.o func2.o./myprog

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

Как правило, вы хотите, чтобы файл заголовка был включен только один раз, это назначение макросов #ifndef #define #endif в файлах заголовков.


5

Сначала вы должны изучить разницу между объявлением и определением . Объявление сообщает компилятору, что что-то вроде функции существует. В случае функций определение — это фактическая реализация функции.

Итак, вам нужно переместить определение в другой файл, но добавить объявление в тот файл, в котором должна быть вызвана функция. . Затем вы собираете оба файла вместе, а компилятор и компоновщик позаботятся обо всем остальном..

Поделиться
отредактировал 1 ноября 2013 в 18:29
user529758
1 нояб. 2013 в 18:26
добавить комментарий |

Сначала вы должны изучить разницу между объявлением и определением . Объявление сообщает компилятору, что что-то вроде функции существует. В случае функций определение — это фактическая реализация функции.

Итак, вам нужно переместить определение в другой файл, но добавить объявление в тот файл, в котором должна быть вызвана функция. . Затем вы собираете оба файла вместе, а компилятор и компоновщик позаботятся обо всем остальном.


-2

Вы можете сделать что-то вроде этого.

 /* func1.c */void func1 (void) {printf ("  Функция 1!  N ");  }/* func2.c */void func2 (void) {printf ("Функция 2!  n");  }/* main.c */#include "func1.c" #include "func2.c" int main (void) {func1 ();  func2 ();  возврат 0;  }  

Поделиться
ответил 01 ноя. : 33
  • Интересно … это тоже работает ( без заголовочного файла). Это почему? — Эндрю 01 нояб., В 18:43
  • 3
    -1: Извините, но … Включение исходных файлов .c возможно в некоторых случаях, но в большинстве случаев нецелесообразно. (Здесь он работает, но не может быть рекомендован, даже если он работает.) В частности, если у вас было два файла, main.c и aux.c (parts одной и той же программы), которые оба должны были использовать func1 () и func2 () , вы не могли использовать этот метод в обоих файлах. Вам понадобится заголовок, чтобы объявить функции для использования хотя бы в одном из файлов main.c и aux.c . Конечно, у вас должен быть заголовок и включать его во все исходные файлы ( main.c , aux.c , func1 .c и func2.c ). — Джонатан Леффлер 01 нояб., 13:45
добавить комментарий |

Вы можете сделать что-то вроде этого.

 /* func1.c */ void func1 (void) {printf ("Функция 1!  n");  }/* func2. c */void func2 (void) {printf ("Функция 2!  n");  }/* main.c */#include "func1.c" #include "func2.c" int main (void) {func1 ();  func2 ();  возврат 0;  }  

Оцените статью
Botgadget.ru
Добавить комментарий