Директивы препроцессоря и заголовочные файлы

Все о программировании под *nix
Аватара пользователя
Speccyfan
Неотъемлемая часть форума
Сообщения: 540
Зарегистрирован: 18 дек 2004, 15:15
Откуда: Polotsk
Контактная информация:

Директивы препроцессоря и заголовочные файлы

Сообщение Speccyfan »

Здравстуйте! Есть вопрос по директивам препроцессора Си и по подключению заголовочных файлов.

На данный момент есть прога, состоящая из:

sf.cpp - основной файл
sf.h - заголовочный к нему
dialog.cpp - еще один файл
dialog.h - к нему заголовочный, он инклудится в sf.cpp
structure.h - файл содержащий структуру с которой работает прога

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

создаю файл например quicksort.cpp вставляю туда код трех функций, делаю файл quicksort.h
в нем:

#ifndef quicksortH
#define quicksortH
void quicksort(int f);
int partition(void *arr_el[], int a, int b, int f);
void quicksortr(void *m[],int a,int b, int f);
#endif

По образу и подобию сделаны все заголовочные файлы.
В файлах sf.cpp и sf.h коментирую то, что перенес в другой файл.

в Makefile добавляю quicksort.o, он у меня такой:

CC = g++ -g

all: sf
sf: sf.o dialog.o quicksort.o -lncurses

clean:
rm -f *.o *.a sf

в файл dialog.cpp добавляю #include "quicksort.h"
в quicksort.cpp добавляю несколько инклудов:
#include "sf.h"
#include "quicksort.h"
#include <stdlib>
#include <string>

пытаюсь собрать.

g++ -c -o quicksort.o quicksort.cpp
quicksort.cpp: In function ‘void quicksort(int)’:
quicksort.cpp:17: ошибка: нет декларации ‘Curr’ в этой области видимости
quicksort.cpp: In function ‘int partition(void**, int, int, int)’:
quicksort.cpp:27: ошибка: нет декларации ‘RECORD’ в этой области видимости
quicksort.cpp:27: ошибка: нет декларации ‘t’ в этой области видимости
quicksort.cpp:28: ошибка: нет декларации ‘TRANZ’ в этой области видимости
quicksort.cpp:28: ошибка: нет декларации ‘elj’ в этой области видимости
quicksort.cpp:29: ошибка: нет декларации ‘elb’ в этой области видимости
quicksort.cpp:30: ошибка: нет декларации ‘eli’ в этой области видимости
quicksort.cpp:33: ошибка: expected primary-expression before ‘)’ token
quicksort.cpp:33: ошибка: expected `;' before ‘arr_el’
quicksort.cpp:34: ошибка: expected primary-expression before ‘)’ token
quicksort.cpp:34: ошибка: expected `;' before ‘arr_el’
quicksort.cpp:35: ошибка: expected primary-expression before ‘)’ token
quicksort.cpp:35: ошибка: expected `;' before ‘arr_el’
make: *** [quicksort.o] Ошибка 1
[speccyfan@localhost kurs]$

Ну понятно не видит структуру и соотвественно указатели, добавляю #include "structure.h"
Получается вот что:

[speccyfan@localhost kurs]$ make
g++ -c -o quicksort.o quicksort.cpp
g++ -g sf.o dialog.o quicksort.o /usr/lib/libncurses.so -o sf
quicksort.o:(.bss+0x4): multiple definition of `Curr'
sf.o:(.bss+0x4): first defined here
quicksort.o:(.bss+0x0): multiple definition of `Head'
sf.o:(.bss+0x0): first defined here
quicksort.o:(.bss+0x8): multiple definition of `End'
sf.o:(.bss+0x8): first defined here
collect2: выполнение ld завершилось с кодом возврата 1
make: *** [sf] Ошибка 1
[speccyfan@localhost kurs]$

Дейсвтительно structure.h инклудится и в сам sf.cpp, как бьть ?
конструкции виде #ifndef не помогают :(

Можно как-нибудь намутить, что б это все собралось ?
Best Regards, Yury Konovalov aka Speccyfan (2:453/53)
Registered Linux User #379588

Аватара пользователя
red f0x
Неотъемлемая часть форума
Сообщения: 338
Зарегистрирован: 08 мар 2004, 01:41

Сообщение red f0x »

Сперва вопрос не совсем по существу... А зачем делать так?
g++ -g sf.o dialog.o quicksort.o /usr/lib/libncurses.so -o sf
опция -l не поддерживается используемой Вами версией g++ и -lncurses не прокатит? ;)

И накрайняк, есть ведь make "макросы" - $@ для выходного файла для данного make-таргета, и $< для входных файлов...

А где имеет место быть Curr? Это переменная или структура? Если переменная и к тому же инициализированная, то она может быть объявлена только в .срр файле. И если она должна быть видна из коду в другом .срр файле, то надо бы сделать extern. Это уже не имеет отношения к директивам. Если это не инициализированная переменная, то может быть объявлена и в хедере. Короче, не совсем понятно, откуда и куда у Вас этот Curr. Судя по регистру и негласному соглашению (которого придерживаются далеко не все :) ) TRANZ и RECORD - это должны бы быть не переменные, а типы...

Чтобы не путаться, было бы наверно лучше сделать все включения Ваших заголовков в sf.h, скажем или в какой-нибудь common.h с объявлениями, используемыми разными частями программы и включать его во все .срр .

В общем, чесгря, затрудняюсь дать точный ответ.
Ну какая работа со строками может быть в языке, название которого является не строкой, а символом? (c) Sergue E. Leontiev

Аватара пользователя
Speccyfan
Неотъемлемая часть форума
Сообщения: 540
Зарегистрирован: 18 дек 2004, 15:15
Откуда: Polotsk
Контактная информация:

Сообщение Speccyfan »

red f0x писал(а):Сперва вопрос не совсем по существу... А зачем делать так?
g++ -g sf.o dialog.o quicksort.o /usr/lib/libncurses.so -o sf
опция -l не поддерживается используемой Вами версией g++ и -lncurses не прокатит? ;)
Будьте внимательней, у меня именно так и сделано, Вы просто немного не туда посмотрели ;-)
И накрайняк, есть ведь make "макросы" - $@ для выходного файла для данного make-таргета, и $< для входных файлов...
Спасибо учту, я просто только начал изучать Си и еще не писал никогда Make файлов.
А где имеет место быть Curr? Это переменная или структура? Если переменная и к тому же инициализированная, то она может быть объявлена только в .срр файле. И если она должна быть видна из коду в другом .срр файле, то надо бы сделать extern. Это уже не имеет отношения к директивам. Если это не инициализированная переменная, то может быть объявлена и в хедере. Короче, не совсем понятно, откуда и куда у Вас этот Curr. Судя по регистру и негласному соглашению (которого придерживаются далеко не все :) ) TRANZ и RECORD - это должны бы быть не переменные, а типы...

Чтобы не путаться, было бы наверно лучше сделать все включения Ваших заголовков в sf.h, скажем или в какой-нибудь common.h с объявлениями, используемыми разными частями программы и включать его во все .срр .

В общем, чесгря, затрудняюсь дать точный ответ.
TRANZ и RECORD это действительно не переменные, а структуры, вот файл
structure.h:

Код: Выделить всё

#ifndef structureH
#define structureH

typedef struct RECORD{
	char marka[9];
	int type;
	float ik;
	float uk;
	float fw;
}RECORD;

typedef struct _TRANZ {
		RECORD * data;
		struct _TRANZ *Next,*Prev;

}TRANZ;


	TRANZ *Head=NULL, *Curr=NULL, *End=NULL;
#endif
Я попробую еще использовать extern, а если не получиться, могу выслать исходники, сможете посмотреть ?
Best Regards, Yury Konovalov aka Speccyfan (2:453/53)
Registered Linux User #379588

Аватара пользователя
Speccyfan
Неотъемлемая часть форума
Сообщения: 540
Зарегистрирован: 18 дек 2004, 15:15
Откуда: Polotsk
Контактная информация:

Сообщение Speccyfan »

сделал extern TRANZ *Head=NULL, *Curr=NULL, *End=NULL;

вот что пишет:

Код: Выделить всё

[speccyfan@localhost kurs]$ make
g++    -c -o sf.o sf.cpp
structure.h:19: предупреждение: ‘extern’ декларация ‘Head’ с инициализацией
structure.h:19: предупреждение: ‘extern’ декларация ‘Curr’ с инициализацией
structure.h:19: предупреждение: ‘extern’ декларация ‘End’ с инициализацией
g++    -c -o dialog.o dialog.cpp
g++    -c -o quicksort.o quicksort.cpp
structure.h:19: предупреждение: ‘extern’ декларация ‘Head’ с инициализацией
structure.h:19: предупреждение: ‘extern’ декларация ‘Curr’ с инициализацией
structure.h:19: предупреждение: ‘extern’ декларация ‘End’ с инициализацией
g++ -g   sf.o dialog.o quicksort.o /usr/lib/libncurses.so   -o sf
quicksort.o:(.bss+0x4): multiple definition of `Curr'
sf.o:(.bss+0x4): first defined here
quicksort.o:(.bss+0x0): multiple definition of `Head'
sf.o:(.bss+0x0): first defined here
quicksort.o:(.bss+0x8): multiple definition of `End'
sf.o:(.bss+0x8): first defined here
collect2: выполнение ld завершилось с кодом возврата 1
make: *** [sf] Ошибка 1
[speccyfan@localhost kurs]$
т.е. особо ничго не изменилось :(
Best Regards, Yury Konovalov aka Speccyfan (2:453/53)
Registered Linux User #379588

Аватара пользователя
red f0x
Неотъемлемая часть форума
Сообщения: 338
Зарегистрирован: 08 мар 2004, 01:41

Сообщение red f0x »

Точно, извиняюсь п/п -l .
А вот остальное... Блин, я не любитель С++, честно говоря , но что-то тут есть, что противоречит здравому смыслу, ИМХО. Может это специфика С++, но в С такое точно невозможно в заголовке:
TRANZ *Head=NULL, *Curr=NULL, *End=NULL;
Эти нициализированные переменные должны быть объявлены единожды и в .срр файле, по идее (если с инициализацией). Если Вы их объявляете в .срр файле, то их соотв. надо убрать из заголовка. Далее, при "импорте" переменных в другой .срр файл с пом. extern инициализировать их не надо. Надо сделать просто extern TRANZ *Head, например.
Ну какая работа со строками может быть в языке, название которого является не строкой, а символом? (c) Sergue E. Leontiev

Аватара пользователя
red f0x
Неотъемлемая часть форума
Сообщения: 338
Зарегистрирован: 08 мар 2004, 01:41

Сообщение red f0x »

Вот Вам пример на С:
файл нумбер 1:

Код: Выделить всё

f0x@devel1:~/tmp$ cat ./struct.h
#ifndef _STRUCT_H_
#define _STRUCT_H_

struct dummy_struct {
    unsigned field0;
    unsigned field1;
};

#endif  /* !_STRUCT_H_ */
Файл №2, в котором декларируется переменная типа dummy_struct и где она инициализируется:

Код: Выделить всё

f0x@devel1:~/tmp$ cat ./stub.c
#include "struct.h"

struct dummy_struct dummy = { 0, 1 };
Основной файл:

Код: Выделить всё

f0x@devel1:~/tmp$ cat ./main.c
#include <stdio>
#include "struct.h"

extern struct dummy_struct dummy;

int main ()
{
        printf ("field0=%d, field1=%d\n", dummy.field0, dummy.field1);
        return 0;
}
Далее, делаем (вручную):

Код: Выделить всё

f0x@devel1:~/tmp$ gcc -o stub.o -c stub.c
In file included from stub.c:1:
struct.h:9:25: warning: no newline at end of file
f0x@devel1:~/tmp$ gcc -o main.o -c main.c
In file included from main.c:2:
struct.h:9:25: warning: no newline at end of file
f0x@devel1:~/tmp$ gcc -o main main.o stub.o
Проверяем работу:

Код: Выделить всё

f0x@devel1:~/tmp$ ./main
field0=0, field1=1
Voila! Что и требовалось... Надеюсь, что чем-то помог.
Ну какая работа со строками может быть в языке, название которого является не строкой, а символом? (c) Sergue E. Leontiev

Аватара пользователя
Speccyfan
Неотъемлемая часть форума
Сообщения: 540
Зарегистрирован: 18 дек 2004, 15:15
Откуда: Polotsk
Контактная информация:

Сообщение Speccyfan »

Спасибо! Помогло! :)
Best Regards, Yury Konovalov aka Speccyfan (2:453/53)
Registered Linux User #379588

Ответить