2015-03-10 6 views
0

Сводка на C сбивает с толку как ад. У меня есть переменная: «int qwe». Этот var должен быть видимым в одном или нескольких файлах - f1.c в этом случае, но не в другом f2.c.C - extern, статические, включают

сказать, что я: main.c, f1.c, f2.c, header.h

главное: вызова f1(); вызов f2();

Заголовок:

#ifndef HEADER_INCLUDED 
#define HEADER_INCLUDED 

int qwe = 1; 
void f1(); 
void f2(); 
#endif // HEADER_INCLUDED 

f1.c:

#include <stdio.h> 

extern int qwe; 

void f1(){ 
    printf("In f1: %d\n", qwe); 
} 

f2.c:

#include <stdio.h> 

static int qwe = 2; 

void f2(){ 
    printf("In f2: %d\n", qwe); 
} 

Теперь это становится запутанным. Существует определение и декларация. Я определил qwe в заголовке, объявив его в файле f1.c. Это верно? Должно ли определение быть в заголовке и декларации в f1.c вместо? Я попробовал последний случай, но получил ошибку - «множественное определение qwe». Когда я удалил директиву #include из f1.c, он работал ... Он также работает, когда я удаляю ключевое слово extern. Является ли extern избыточным?

f2.c Я предполагаю, что все в порядке и ведет себя так, как ожидалось, или это так? Но если я поставлю заголовок #include с заголовком, он сломается. Почему это?

Когда я должен использовать #include в исходных файлах? Если я не включаю его f1.c или f2.c, он работает ...

Также, если я определяю переменную как статическую внутри функции, например static int i = 0; Эта переменная не будет уничтожена, если функция существует, она сохранит ее память и данные. И в следующий раз, когда эта же функция будет вызвана, у нее будет доступ к ней, правильно? Но var не будет повторно инициализирован до 0, т. Е. Строка, где определяется, не будет выполняться. Верный?

Жизнь плющит меня :(

+0

Забыто явно уточнить, что если #include «header» помещается в f1.c, не удается скомпилировать с ошибкой: «множественное определение qwe» и «первое определение здесь». Почему это? – user2092119

+0

Файл заголовка должен содержать объявление, а не определение. Положите определение в f1.c. Либо не включать заголовочный файл в f2.c, либо скрывать объявление с помощью # #define qwe qwehidden. – chqrlie

+0

Правило большого пальца: если вы когда-либо обнаруживаете, что используете ключевое слово 'extern' для непостоянных переменных, ваш дизайн программы нарушен. – Lundin

ответ

1

В C, вы должны использовать файл заголовок вообще объявить данных, но не определить данных. Вы не хотите определять глобальные данные в заголовке, потому что тогда он будет избыточно определен в нескольких модулях. Заголовок указывает на несколько модулей существование каких-либо данных или функций где-то и каков его тип, а также общие константы и макросы (#define s). Вне этого, вещи в C очень просты. Все, что угодно, технически глобально, если вы не объявите его static, сохраняя его в модуле, это определено. Объявления extern для данных в заголовках и прототипа функций помогают компилятору знать, что к этим элементам обращаются конкретный модуль и типы данных для доступа, чтобы можно было создать правильный код.

У вас есть:

  • Две функции f1 и f2, которые определены в отдельных модулях, но используется в main. Поэтому они должны быть объявлены в файле заголовка.

  • Глобальный элемент данных qwe используется в нескольких модулях.

  • A Статическийqwe Используется в одном модуле.

Предполагая, что вы хотите это сделать с одним файлом заголовка (вам может понадобиться отдельные из них для f1, f2 и глобальные данные - смотри ниже), вы можете настроить ваш заголовок как:

#ifndef MY_HEADER_H 
#define MY_HEADER_H 

extern int qwe; 

void f1(void); 
void f2(void); 
#endif // MY_HEADER_H 

Тогда в вашем main.c:

... 
#include "my_header.h" 

int qwe; // This is global and can be accessed from other modules 

void main(...) 
{ 
    // call f1 
    // call f2 
    ... 

Я просто определил глобальную переменную, qwe в main.c произвольно. Если у вас есть несколько глобалов, вы можете определить их в своем собственном glob_data.c модуле, например, и иметь собственный заголовок, glob_data.h, до объявить им. Любой другой модуль, который должен получить к ним доступ, будет включать заголовок glob_data.h, чтобы можно было правильно выполнить компиляцию на этом модуле для доступа к этим данным. Сохранение глобальных данных в отдельных заголовках помогает в таких случаях, когда у вас есть экземпляр static данных против глобального, которые находятся в конфликте. Вы можете избежать включения файла заголовка данных для этого глобального элемента, когда вы хотите скомпилировать элемент static.

Затем в файле C, f1.c:

...system headers included... 
#include "my_header.h" 

void f1() { 
    printf("In f1: %d\n", qwe); 
} 

И в f2.c:

...system headers included... 
#include "my_header.h" // Only if it doesn't contain `extern int qwe;` 

static int qwe = 2; // This hides the global qwe and is known only 
         // to f2.c 

void f2(){ 
    printf("In f2: %d\n", qwe); 
} 

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

+0

Прежде всего, спасибо вам за разъяснение. Книга, которую я использую, не была достаточно подробной для этих вещей или предполагала более высокий уровень интеллекта: D @lurker Теперь я пробовал это и получил ошибку в f2.c, заявив, что «статическая декларация qwe следует за статической декларации "и что" предыдущее объявление qwe было здесь ". Это исправлено, удалив директиву #include. – user2092119

+0

@ user2092119, эта ошибка является хорошей причиной для создания заголовка данных с 'extern in qwe;' separate, так что его необязательно включать, но если вы хотите включить объявления для 'f1' и/или 'f2'. – lurker

+0

спасибо, я буду помнить об этом. Вы, ребята, потрясающие: D – user2092119

2

В заголовке, объявить переменную. В, например, f1.c, определить переменную, например int qwe = 1; // в глобальном масштабе.

во всех файлах, которые хотят увидеть/изменить qwe, включают в себя заголовок, объявляющий переменную. Easy-Peasy.

1

I have defined qwe in the header, declared it in f1.c . Is that correct?

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

When should i use #include in source files?

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

Also, if I define a variable as static inside a function, like static int i = 0; This variable will not be destroyed when function exist, it will keep it's memory and data.

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

2

Вы должны объявить переменной в заголовке, и определяют его в одном и только один C файл.

В C вы не можете иметь переменную, которая не относится к данной единицы перевода (исходный файл). Поэтому он должен быть определен только одной единицей перевода во всей программе.

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

Это, вероятно, также стоит отметить, что, когда вы пытаетесь объявить переменную безextern, переменная также определяется, например:

/* Declares, but does not defines external symbol 'foo' */ 
extern int foo; 

/* Both declares AND defines bar */ 
int bar; 

Это также отличается от того, как функции работают, туда, где «по умолчанию» синтаксис декларации не определяет функцию:

/* Declare, but don't define spam */ 
void spam(void); 

/* Declare, but don't define eggs */ 
extern void eggs(void); 

/* Declare & define 'cheese' */ 
void cheese(void){ return; } 

Так что ваш пример должен выглядеть следующим образом:

qwe.h:

#ifndef QWE_H 
#define QWE_H 
/* Declare qwe here */ 
extern int qwe; 
#endif 

f1.c:

/* DEFINE qwe here */ 
int qwe = 1; 

f2.c:

#include "qwe.h" /*header includes the `extern int qwe` declaration */ 
void my_function(void) 
{ 
    /* use external symbol here! */ 
    qwe = 10; 
} 
2

Система обзорное не так сбивает с толку. Правило таково:

  • если вы определяете что-то в .c файла КАЖДОГО другой файл .c в программе может получить доступ к нему (он помещается в глобальном пространстве имен).

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

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

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

 Смежные вопросы

  • Нет связанных вопросов^_^