Вопросы по С/С++ (СИ)

Если ваш вопрос не влез ни в одну из вышеперечисленных тем, вам сюда.
Ответить
Модератор
Аватара пользователя
Сообщения: 4618
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля

Сообщение Аlex »

Не поможет Вам эта директива. Что с ней, что без неё будет одинаковый результат.
что файл обрабатывается компилятором лишь единожды
Заблуждение !
Она лишь гарантирует, что один и тот же хидер не будет подключен многократно в одном модуле !

ЗЫ: И по вышеприведённой ссылке всё написано правильно. Там писал человек, уровнем выше некоторых тут присутствующих на несколько голов.
Реклама
ks0
Прорезались зубы
Аватара пользователя
Сообщения: 238
Зарегистрирован: Чт фев 28, 2013 14:16:10

Сообщение ks0 »

Это же легко проверить

Изображение
Реклама
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18788
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

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

так вот. каждый элемент программы в Си может иметь:
1. объявление или описание
2. определение или реализация
3. использование

объявление - это информация компилятору о наличии некоей сущности с характерными свойствами. для переменной - это ее тип, для функции кроме типа еще и типы ее параметров.

определение - это наполнение упомянутой сущности реальным смыслом. для переменной это присваивание начального значения, для функции - реализация ее тела.

использование - это, само собой, использование сущности в алгоритме.

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

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

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

extern int var;
int var;
// тут нет никаких ошибок!
а вот попытка в хидере определить переменную - это крайне порочная практика, такая же, как подключение директивой include исходника на Си #include "myfile.c".
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
Модератор
Аватара пользователя
Сообщения: 4618
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля

Сообщение Аlex »

ks0 писал(а):Это же легко проверить
Изображение
Понятия не имею, что Вы этим "проверили"...

http://os24.org/files/books/Brian_Kerni ... age-RU.pdf стр. №89 , п. 4.11.1
Процитирую один момент, о котором я уже выше говорил :
Любая строка вида
#include "имя-файла"
заменяется содержимым файла с именем имя-файла.
. Т.е. , как уже было сказано выше, include - всего-лишь вставляет текст подключаемого файла в код !
Реклама
Эиком - электронные компоненты и радиодетали
ks0
Прорезались зубы
Аватара пользователя
Сообщения: 238
Зарегистрирован: Чт фев 28, 2013 14:16:10

Сообщение ks0 »

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

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

extern int var;
int var;
// тут нет никаких ошибок!
Удивился этому изврату, протестировал, оказывается работает... Но дело вообще вот в чем. Каждый файл .с (как и .h) компилируется отдельно, на его основе создаются некие промежуточные файлы .o (объектный). Затем проходит компоновщик и связывает это все в один исполняемый файл. Вот если у вас некая переменная объявлена в одном .с файле, и вы хотите её использовать и в другом, то нужен способ как-то на нее сослаться. Если вы просто попытаетесь использовать её по имени, компилятор, при обработке выругается, т.к. ничего не знает о существовании того файла, где она была объявлена (они же проходится независимо). Вот тут и используется extern, мы как бы говорим компилятору "Мамой клянусь, где-то есть такая глобальная переменная". Он соглашается. Потом проходит компоновщик, и находит её в другом объектов файле, и вставляет на нее ссылку. А если не находит, то ругается уже компоновщик, и программа не собирается.

Поэтому extern редкоиспользуемый костыль, если есть .h файл, то достаточно переменную объявить там.
Реклама
Модератор
Аватара пользователя
Сообщения: 4618
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля

Сообщение Аlex »

ks0 писал(а):Вот тут и используется extern, мы как бы говорим компилятору "Мамой клянусь, где-то есть такая глобальная переменная". Он соглашается. Потом проходит компоновщик, и находит её в другом объектов файле, и вставляет на нее ссылку
Дак вот для этого они (переменные) и описываются в .h-файле с квалификатором extern, чтобы при его подключении, в модуле появлялась ссылка на эти переменные, которые находятся в другом модуле. Какой же это костыль ?
Ещё раз говорю: подключение файла с помощью директивы #include - это всего-лишь вставка в файл текста из подключаемого файла, не более того ! Отсюда следует логический вывод - если Вы напишите объявление переменной в подключаемом .h-файле, то это будет равносильно тому, что Вы объявите эти переменные во всех файлах, в которых подключали этот .h-файл.
Естественно, после подобных манипуляций, во всех файлах создадутся совершенно разные переменные (с разными адресами), просто с одинаковым именем.
Реклама
ks0
Прорезались зубы
Аватара пользователя
Сообщения: 238
Зарегистрирован: Чт фев 28, 2013 14:16:10

Сообщение ks0 »

Аlex писал(а):Понятия не имею, что Вы этим "проверили"...
Ну Вы сказали, что "будут созданы отдельные экземпляры переменной var, с разными адресами"
А получился один экземпляр, и с одним адресом.
Аlex писал(а):Т.е. , как уже было сказано выше, include - всего-лишь вставляет текст подключаемого файла в код !
Вы или неправильно понимаете, или там так неудачно сформулировано.
Вот в более новых языках программирования существует такое понятие как "пространство имен", в классическом Си его нет, или под ним понимается что-то другое. Пространство имен (namespace) собирает все определения созданные внутри него в единое множество. Может быть несколько П.И. и они могут иметь одинаковые объявления, например int var в одном и int var в другом это абсолютно разные переменные. Если П.И. не задано, то используется некое глобальное П.И. Так вот в Си существует только одно глобальное пространство имен. Переменная с именем var это всегда одна и та же переменная (если только не объявлена внутри функции).
ks0
Прорезались зубы
Аватара пользователя
Сообщения: 238
Зарегистрирован: Чт фев 28, 2013 14:16:10

Сообщение ks0 »

Аlex, вероятно Вы правы все-таки. Только тогда разобраться надо почему GCC это лопает.
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18788
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

что лопает? объявление одноименных локальных переменных в разных модулях? так это по стандарту можно. вот как программист потом разберется в них - это другой вопрос :)
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
ks0
Прорезались зубы
Аватара пользователя
Сообщения: 238
Зарегистрирован: Чт фев 28, 2013 14:16:10

Сообщение ks0 »

ARV писал(а):что лопает? объявление одноименных локальных переменных в разных модулях?
По объявлению в .h создает одну переменную, а не две. См. картинку выше. Компоновщик не ругается. Книжки по С++ однозначно такую конструкцию запрещают. В Си все должно быть еще однозначнее :\
Короче пойду умных людей подопрашиваю. GCC вообще уже не первый раз меня удивляет.
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18788
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

ks0 писал(а):
ARV писал(а):что лопает? объявление одноименных локальных переменных в разных модулях?
По объявлению в .h создает одну переменную, а не две. См. картинку выше.
картинка выше ничего не показывает, т.к. отладчик ловит контекст и показывает переменную по контексту. посмотрите map-файл - вот если там действительно память будет под одну переменную - тогда на самом деле странно...
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
ks0
Прорезались зубы
Аватара пользователя
Сообщения: 238
Зарегистрирован: Чт фев 28, 2013 14:16:10

Сообщение ks0 »

ARV писал(а):картинка выше ничего не показывает, т.к. отладчик ловит контекст и показывает переменную по контексту. посмотрите map-файл - вот если там действительно память будет под одну переменную - тогда на самом деле странно...
Да одна, и дизассемблер по одному адресу отработку показывает.
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18788
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

да я и сам сейчас смотрю в map-файл, и вижу, что одна :( причем если static делать в обоих модулях, то получается две. если static только в одном - одна... но если без static попробовать проинициализировать разными числами - вылетает ошибка линкера "multiple definition"... странно все это...
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
pcb
Опытный кот
Сообщения: 833
Зарегистрирован: Пт авг 12, 2011 09:14:27
Откуда: Млечный путь/Земля/РФ/Екатеринбург

Сообщение pcb »

Да одна
Файлик map подцепи.

Вот
http://msdn.microsoft.com/ru-ru/library/s1sb61xd.aspx
Разработал:
-BLDC
-ФУОЗ/МПСЗ
-SMART BMS
-ECU/EDC на STM32F4(43%)+CPLD(57%)
-Моноинжектор на ATSAMD20G16
-контроллер эффектов для RGB LED ленты
-умные часы/обратный счет/секундомер
-устройство измерения емкости АКБ
ks0
Прорезались зубы
Аватара пользователя
Сообщения: 238
Зарегистрирован: Чт фев 28, 2013 14:16:10

Сообщение ks0 »

Докладываю.

"Так можно делать в С, это tentative definition, объект обявленный таким образом попадает в область общих данных. При линковке одноимённые объекты в этой области становятся одним объектом. В С++ так делать нельзя."

tentative definition гуглится, вопросы такого планы уже были.
Например вот.
The ANSI C standard supports the concept of the tentative definition. Any external data declaration that has no storage class specifier and no initializer is considered a tentative definition. If the identifier declared appears in a later definition, then the tentative definition is treated as if the extern storage class specifier were present. In other words, the tentative definition becomes a simple referencing declaration.

If the end of the translation unit is reached and no definition has appeared with an initializer for the identifier, then the tentative definition becomes a full definition, and the object defined has uninitialized (zero-filled) space reserved for it.

Unlike ANSI C, C++ doesn't have the concept of a tentative declaration; an external data declaration without a storage class specifier is always a definition.
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18788
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

Страшная вещь этот Си... Чем глубже его узнаю, тем больше уверен, что его создатели без ЛСД не обошлись...
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
Друг Кота
Аватара пользователя
Сообщения: 20117
Зарегистрирован: Чт сен 18, 2008 12:27:21
Откуда: Столица Мира Санкт-Петербург

Сообщение Gudd-Head »

А теперь суммируя всё вышеизложенное, можно по-русски и для чайников — чего-как правильно надо делать и какие могут быть подводные камни? :)
[ Всё дело не столько в вашей глупости, сколько в моей гениальности ] [ Правильно заданный вопрос содержит в себе половину ответа ]
Держит паяльник хвостом
Аватара пользователя
Сообщения: 960
Зарегистрирован: Вс дек 02, 2012 16:58:33
Откуда: от туда

Сообщение GARMIN »

Для использования глобальных переменных в разных файлах делаем так:
В файле sample.h:

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

extern char s1;
в файле main.c:

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

#include "sample.h"
char s1 = INIT_S1;
в других файлах:

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

#include "sample.h"
s1 = 2;
Указание типа с extern без присваивания -> объявление переменной в том файле, где применяете, без выделения памяти.
Указание переменной с типом и присвоением значения -> определение переменной (выделение памяти).
Использование переменной дальше без ограничений.
Лишний extern в main.c никак не мешает выделять память при определении переменной.
Контактная информация:
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18788
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

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

Мой уютный бложик... заходите!
Контактная информация:
Друг Кота
Аватара пользователя
Сообщения: 20117
Зарегистрирован: Чт сен 18, 2008 12:27:21
Откуда: Столица Мира Санкт-Петербург

Сообщение Gudd-Head »

любом.... месте?
[ Всё дело не столько в вашей глупости, сколько в моей гениальности ] [ Правильно заданный вопрос содержит в себе половину ответа ]
Ответить

Вернуться в «Разные вопросы по МК»