2015-01-19 9 views
2

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

Я нахожусь в процессе самообучения с использованием книги C Primer Plus (Короче, я новичок в C). Я почти закончил читать всю книгу и работал над упражнениями для каждой главы, и время от времени я уходил по касательной. Это как-раз тот случай. Я столкнулся с особой проблемой, и я уверен, что это связано с директивами препроцессора.

Я использую MinGW (GCC для Windows) и сообщает:

Ошибка, отчеты GCC является:

nanfunct.c: несколько определение
nanite.c 'ключевые слова': первая определяется здесь
и т.д ... и т.д ... больше ошибок ...

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

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

, например:

#ifndef MENU_OPTIONS 
# define MENU_OPTIONS ON 
# if MENU_OPTIONS == ON 
     ...some code here... 

     char * keywords[] = { 
      "copy", "help", "line", 
      "quit", "read", "write" 
     }; 

     char * keyletters[] = { 
      "c", "h", "l", 
      "q", "r", "w" 
     }; 
# endif 
#endif 

Я использую три файл:

nanite.c -> исходного файл для основных()
nanfunct.c -> исходного файла для функций
nanproto.h -> файл заголовка для nanite.c и nanfunct.c

Внутри nanite.c и nanfunct.c I #includenanproto.h

исходные файлы, размещенные на Pastebin:
nanproto.h -> Заголовочный файл для nanite.c и nanfunct. с
nanite.c & nanfunct.c -> исходных файлов

Почему это происходит? Я думал, что #ifndef должен был продолжать подобные вещи?

ответ

4

Вы неправильно понимаете, что делает препроцессор, или как исходные файлы C скомпилированы и связаны.

Каждый исходный файл предварительно обрабатывается отдельно. Таким образом, после предварительной обработки nanfunct.c содержит определения keywords и keyletters. Затем предварительно обработанный источник компилируется в файл объекта nanfunct.o.

После предварительной обработки nanite.c также содержит определения keywords и keyletters. Этот предварительно обработанный источник скомпилирован для создания объектного файла nanite.o.

Затем компоновщик пытается объединить nanfunct.o и nanite.o. Он обнаружил, что существует более одного определения keywords и keyletters, поэтому отображается сообщение об ошибке и прерывается.

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

Переместить это:

char * keywords[] = { 
     "copy", "help", "line", 
     "quit", "read", "write" 
}; 

char * keyletters[] = { 
     "c", "h", "l", 
     "q", "r", "w" 
}; 

в любой nanite.c или nanfunct.c (но не оба). Добавьте эти объявления в nanite.h:

extern char * keywords[]; 
extern char * keyletters[]; 

Таким образом, эти определения включены только в одном файле объекта.

Обратите внимание, что это относится только к глобальным переменным и функциям. Это не относится к структурам, объединениям, перечислениям или typedefs, поскольку они не включены в объектные файлы.

2

Вы ошиблись, поставив определения в свои .h файлы. Только объявления входят в .h файлы.

Если поставить это (определение):

char * keywords[] = { "foo" }; 

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

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

Ваш файл .h должен иметь что-то вроде этого:

extern char *keywords[]; 

А потом точно один .c файл должен обеспечить определение.

+0

Кому-то, кто не понимает, как работают компиляторы, явно было дано слишком мало голосов в свое время здесь. –

+0

Я проигнорировал это, потому что, прежде чем вы неоднократно редактировали его, это был не очень полезный ответ. – immibis

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