Перейти из форума на сайт.

НовостиФайловые архивы
ПоискАктивные темыТоп лист
ПравилаКто в on-line?
Вход Забыли пароль? Первый раз на этом сайте? Регистрация
Компьютерный форум Ru.Board » Компьютеры » Прикладное программирование » Проблема с pragma once и include guard

Модерирует : ShIvADeSt

 Версия для печати • ПодписатьсяДобавить в закладки

Открыть новую тему     Написать ответ в эту тему

DamnCliffracers

Newbie
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
Имеется три файла:
 
1.h - содержит объявления разных полезных констант, переменных, прототипов функций
1.cpp - содержит реализации функций, объявленных в 1.h. К нему подключается 1.h
2.h - описывает форму. В этом файле используется функции, объявленные в 1.h. Соответственно, к нему тоже подключается 1.h.
 
В 1.h прописана директива #pragma once. Но при сборке возникают многочисленные ошибки LNK2005 - "переменная такая-то уже определена в файле таком-то". Аналогично при использовании include guard, а также #pragma once и include guard одновременно.
Подозреваю, что я что-то делаю не так, но что?

Всего записей: 13 | Зарегистр. 27-02-2017 | Отправлено: 11:59 27-02-2017 | Исправлено: DamnCliffracers, 12:12 27-02-2017
ne_viens

Advanced Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
Глобальные переменные надо объявлять в cpp файлах а не в h.
В одном из них int g_var0, в остальных extern int g_var0

Всего записей: 1530 | Зарегистр. 01-11-2004 | Отправлено: 11:42 28-02-2017
akaGM

Platinum Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
а так ещё работает?
 

Код:
в 1.h
 
 
#ifndef ___MY_H_FILE_INCLUDED___
  #define ___MY_H_FILE_INCLUDED___
 
  int g_var0;
...
#endif //___MY_H_FILE_INCLUDED___

Всего записей: 24113 | Зарегистр. 06-12-2002 | Отправлено: 16:55 01-03-2017
Abs62



Gold Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
akaGM

Цитата:
а так ещё работает?

Так будет работать при условии, что 1.h включается в один и только один .cpp. Что само по себе делает разбиение на .h и .cpp восхитительно бессмысленным.

----------
0 программистов ругал сердитый шеф
Потом уволил одного, и стало их FF

Всего записей: 6080 | Зарегистр. 22-10-2005 | Отправлено: 18:47 01-03-2017
akaGM

Platinum Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
Abs62
 
странно, у меня все мои старые С-проекты именно по такой схеме и построены
либо я что-то не так понимаю, либо одно из двух...
 
короче, ты меня обманываешь :)
 
навскидку, демонстрашка fontedit от M$:
 

Код:

typecvt.c
---------
#include "typecvt.h"
 
fontcvt.c
---------
#include "typecvt.h"
 
typecvt.h
---------
#ifndef _TYPECVT_
  #define _TYPECVT_
#endif  // _TYPECVT_

Всего записей: 24113 | Зарегистр. 06-12-2002 | Отправлено: 22:25 01-03-2017
Abs62



Gold Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
akaGM

Цитата:
короче, ты меня обманываешь

Ни в коем разе.
Не надо путать объявление и определение переменных. Если в .h содержатся только объявления без определений, типа "extern int g_var0;", проблем не будет. Но стоит воткнуть туда определение переменной, "int g_var0;", эта переменная окажется определена в каждом .c/.cpp, куда включён соответствующий хидер. И компоновщик, обнаружив несколько переменных с одинаковым именем, сразу начнёт на них материться.

----------
0 программистов ругал сердитый шеф
Потом уволил одного, и стало их FF

Всего записей: 6080 | Зарегистр. 22-10-2005 | Отправлено: 23:15 01-03-2017
akaGM

Platinum Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
Abs62

Цитата:
int g_var0;", эта переменная окажется определена в каждом .c/.cpp, куда включён  
соответствующий хидер.
это я, сб, понимаю...
разве таблица глобалов не единая для всех файлов проекта и строится по мере, так сказать?

Всего записей: 24113 | Зарегистр. 06-12-2002 | Отправлено: 00:26 02-03-2017
Abs62



Gold Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
akaGM
Строится по мере компоновки. Берутся таблицы экспорта из каждого .obj и сливаются в одну. Дублирование декорированных имён не допускается.

----------
0 программистов ругал сердитый шеф
Потом уволил одного, и стало их FF

Всего записей: 6080 | Зарегистр. 22-10-2005 | Отправлено: 00:52 02-03-2017
akaGM

Platinum Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
ну как туда попадут две копии глобальной, если хидер с ней инклудается/компилится/парсится _один_ раз?!

Всего записей: 24113 | Зарегистр. 06-12-2002 | Отправлено: 01:53 02-03-2017 | Исправлено: akaGM, 06:26 02-03-2017
asutp2

Advanced Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
Разработчики C/C++ знают толк в извращениях ))))

Всего записей: 791 | Зарегистр. 22-10-2004 | Отправлено: 05:55 02-03-2017
Abs62



Gold Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
akaGM

Цитата:
ну как туда попадут две копии глобальной, если хидер с ней инклудается/компилится/парсится _один_ раз?!

Ага, один раз для каждого .c/.cpp, в который включён.

----------
0 программистов ругал сердитый шеф
Потом уволил одного, и стало их FF

Всего записей: 6080 | Зарегистр. 22-10-2005 | Отправлено: 07:36 02-03-2017
akaGM

Platinum Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
да, если он туда включён, так ведь не включается...
чёрт с ним, у меня всё работает и ладно и вообще спать пошёл, а то уже к станку пора :)

Всего записей: 24113 | Зарегистр. 06-12-2002 | Отправлено: 07:42 02-03-2017
Abs62



Gold Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
akaGM

Цитата:
да, если он туда включён, так ведь не включается...

Так с этого я и начал - если такой хидер включается только в один .c/.cpp, то прокатит.

----------
0 программистов ругал сердитый шеф
Потом уволил одного, и стало их FF

Всего записей: 6080 | Зарегистр. 22-10-2005 | Отправлено: 09:18 02-03-2017
DamnCliffracers

Newbie
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору

Цитата:
Ага, один раз для каждого .c/.cpp, в который включён.  

 
Так вроде бы смысл стражей и pragma once как раз в том, чтобы можно было без проблем включать один хедер в разные .cpp?) А на деле что с ними, что без них - разницы не видно

Всего записей: 13 | Зарегистр. 27-02-2017 | Отправлено: 10:53 02-03-2017
Abs62



Gold Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
DamnCliffracers
Нет, смысл в другом. Чтобы не возникало конфликтов при неявном подключении хидеров через другие хидеры. Ну, как-то так:
 
foo.h:

Код:
#include <iostream>
 
void foo(std::ostream & os, int arg);
 

bar.h:

Код:
#include <iostream>
 
void bar(std::ostream & os, int arg);

main.cpp:

Код:
#include <iostream>
#include "foo.h"
#include "bar.h"
 
int main() {
// ...
  foo(std::cout, 10);
  bar(std::cout, 20);
}
 

Вот в такой конструкции хидер iostream по факту включается в один .cpp несколько раз. А потому должен быть защищён от повторной обработки либо гвардами, либо pragma once. Ситуация, встречающаяся даже не часто, а практически постоянно.

----------
0 программистов ругал сердитый шеф
Потом уволил одного, и стало их FF

Всего записей: 6080 | Зарегистр. 22-10-2005 | Отправлено: 11:18 02-03-2017 | Исправлено: Abs62, 11:19 02-03-2017
akaGM

Platinum Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
Abs62

Цитата:
Так с этого я и начал
а я с этого начал и этим кончил...
условной компиляцией, вернее условным включением/невключением, а ты сказал -- не прокатит...

Всего записей: 24113 | Зарегистр. 06-12-2002 | Отправлено: 14:55 02-03-2017
Abs62



Gold Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
akaGM
1.h

Код:
#ifndef ___MY_H_FILE_INCLUDED___
  #define ___MY_H_FILE_INCLUDED___
 
  int g_var0;
...
#endif //___MY_H_FILE_INCLUDED___

1.cpp

Код:
#include "1.h"
...

2.cpp

Код:
#include "1.h"
...

Простой вопрос: будет ли присутствовать "g_var0" в таблицах экспорта 1.obj и 2.obj?

----------
0 программистов ругал сердитый шеф
Потом уволил одного, и стало их FF

Всего записей: 6080 | Зарегистр. 22-10-2005 | Отправлено: 15:10 02-03-2017
akaGM

Platinum Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
Abs62
 
в 1.обж да, во втором -- нет...
а, ну я понял, вообще не будет...
 
на самом деле при внимательном изучении своего :) старого кода тоже не обнаружил реализацию глобалов в инклудниках, только объявления...
нo условное включение есть :)
все вопросы сняты...

Всего записей: 24113 | Зарегистр. 06-12-2002 | Отправлено: 15:33 02-03-2017 | Исправлено: akaGM, 15:34 02-03-2017
Abs62



Gold Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
akaGM

Цитата:
в 1.обж да, во втором -- нет...
а, ну я понял, вообще не будет...

Надо просто помнить, что для компилятора каждый .c/.cpp - отдельная и независимая сущность. Компилятор не занимается установлением взаимосвязей между модулями - это забота компоновщика. И потому инклюды одного модуля не влияют на компиляцию другого. От слова "совсем".

----------
0 программистов ругал сердитый шеф
Потом уволил одного, и стало их FF

Всего записей: 6080 | Зарегистр. 22-10-2005 | Отправлено: 15:41 02-03-2017
akaGM

Platinum Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
и вообще надо писать
 
int aaa;
extern int aaa;
 
:)

Всего записей: 24113 | Зарегистр. 06-12-2002 | Отправлено: 16:22 02-03-2017
Открыть новую тему     Написать ответ в эту тему

Компьютерный форум Ru.Board » Компьютеры » Прикладное программирование » Проблема с pragma once и include guard


Реклама на форуме Ru.Board.

Powered by Ikonboard "v2.1.7b" © 2000 Ikonboard.com
Modified by Ru.B0ard
© Ru.B0ard 2000-2024

BitCoin: 1NGG1chHtUvrtEqjeerQCKDMUi6S6CG4iC

Рейтинг.ru