Перейти к содержанию
    

Определение размера массива на этапе компиляции

2 часа назад, razrab83 сказал:

дупликэйт дифинишин

Так ведь в приличных домах исходниках принято принимать меры против множественного включения:

#ifndef ASD_H
#define ASD_H

int const array[] = {1,2};
#define SIZE_ARRAY (sizeof(array))
  
#endif

Или у вас IAR какой-то неправильный, раз у всех работает, а у вас - нет.  :unknw:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 час назад, jcxz сказал:

Так ведь в приличных домах исходниках принято принимать меры против множественного включения:


#ifndef ASD_H
#define ASD_H

int const array[] = {1,2};
#define SIZE_ARRAY (sizeof(array))
  
#endif

Или у вас IAR какой-то неправильный, раз у всех работает, а у вас - нет.  :unknw:

А вы не видите какой косяк в этом коде, не компилируя его?

"дупликэйт дифинишин"  -  извините за мой французкий duplicate definition. Какая взаимосвязь между "множественным определением" и "множественным включением"?

 

Естественно во всех хидерах есть #ifndef ASD_H. И? В приличных домах обычно, переменные объявляют в хидерах, определяют в исходниках. Включите #include "asd.h" в несколько *.с, компилятор в каждом *.с определит array (мне это зачем?), линкер дает законную ошибку дупликэйт дифинишин Error[Li006]: duplicate definitions for "array";

 

Цитата

раз у всех работает

ps Научитесь держать слово за себя. Все другие сами за себя скажут.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

3 минуты назад, razrab83 сказал:

А вы не видите какой косяк в этом коде, не компилируя его?

В чём именно "косяк"?

3 минуты назад, razrab83 сказал:

Включите #include "asd.h" в несколько *.с, компилятор в каждом *.с определит array (мне это зачем?), линкер дает законную ошибку дупликэйт дифинишин Error[Li006]: duplicate definitions for "array";

И почему у меня на кучу таких включений никаких ни ошибок ни варнингов не выдаётся, а у вас - выдаются? Может стоить поискать причину? У себя.

3 минуты назад, razrab83 сказал:

ps Научитесь держать слово за себя. Все другие сами за себя скажут.

Кроме вас о подобной проблеме больше никто не пишет, соответственно - проблема только у вас.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 часа назад, jcxz сказал:

В чём именно "косяк"?

Нарушено правило ODR. Я же разжевал в чем косяк? См мой пост выше.  Или вы издеваетесь?

Модератор, дайте бан jcxz на пару недель, за издевательство. Может знание по С/С++ подтянет.

2 часа назад, jcxz сказал:

И почему у меня на кучу таких включений никаких ни ошибок ни варнингов не выдаётся, а у вас - выдаются?

Вы хотите сказать, что если вы в двух исходных файлах определите две глобальные переменные с одинаковым именем, то ваш линкер это проглотит? Если да, то вы не на с/с++ пишите. Вам тут не место на другой форум.

2 часа назад, jcxz сказал:

Кроме вас о подобной проблеме больше никто не пишет, соответственно - проблема только у вас.

Ну во первых у меня нет подобной проблемы, т.к. я подобный говнокод не генерирую.

Во вторых, если кто и "оступиться", то компилятор линкер сообщит проблему и она легко правиться, и ни нужно ни куда ни чего писать.

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

 

ps собрал холоворд на gcc с вашим кодом - тоже самое, даже код ошибки такой же. 
 

Цитата

 

multiple definition of `array'

collect2.exe: error: ld returned 1 exit status
make: *** [makefile:65: Li006.elf] Error 1

 

 

6 часов назад, Andrew_Q сказал:

Если перейти к указателю, то проинициализируется


extern const int array_size;

int *qwe = &array_size;

Только я уже не уверен это ли требуется.

Уже не требуется. Сделал именно через указатель. Всё равно спасибо!

Изменено пользователем razrab83

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

16 минут назад, razrab83 сказал:

Вы хотите сказать, что если вы в двух исходных файлах определите две глобальные переменные с одинаковым именем, то ваш линкер это проглотит? Если да, то вы не на с/с++ пишите. Вам тут не место на другой форум.

Может не стоит посылать других куда-то, чтобы самому не быть посланным?

И я вроде достаточно внятно написал, чтобы ещё раз повторять одно и то же. Это "проглатывают" и IAR и VS как минимум. И другие компиляторы должны.

А если у вас с этим проблема (не у меня) - то может стоить выпрямить руки?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

19 минут назад, razrab83 сказал:

Если да, то вы не на с/с++ пишите

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

А если бы переменная была не const и не была проинициализирована - то в сях бы компилилось, а в плюсах нет.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

15 часов назад, Сергей Борщ сказал:

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

Да, в плюсах const int array[] объявленный 2 раза в разных исходниках собирается, без const нет. В си с const - нет. 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

19 часов назад, jcxz сказал:

В чём именно "косяк"?

Стыдно должно быть за такие вопросы.

17 часов назад, razrab83 сказал:

Вы хотите сказать, что если вы в двух исходных файлах определите две глобальные переменные с одинаковым именем, то ваш линкер это проглотит?

На си нет конечно, звездит. Что там jcxz  и чем компилирует - неизвестно. У меня Iar-arm и mingw подавились: multiple definition of `array' ... mingw32-make[1]:... Error 1

Это в стандарте прописано. Пруф -   ISO/IEC 9899:2017        6.9 External definitions

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

17 часов назад, Сергей Борщ сказал:

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

22 minutes ago, dxp said:

то компилятор вынужден будет разместить массив в памяти

Размещением в памяти занимается линкер, а не компилятор. И не размещать несколько копий одного и того же не является проблемой на этом этапе. Хотя не знаю, что там происходит на самом деле.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

4 часа назад, dxp сказал:

Если такое делается во многих единицах трансляции, то будет пачка копий одного и того же массива, что не есть гуд.

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

4 часа назад, rkit сказал:

И не размещать несколько копий одного и того же не является проблемой на этом этапе. Хотя не знаю, что там происходит на самом деле.

Да, например IAR имеет соответствующую опцию компоновщика "--merge_duplicate_sections". Но почему-то она не работает - сейчас попробовал и не смог заставить выполнять объединение копий, хотя по мануалу - должна удалять дубликаты.  :sad:

 

PS: Нашел как заставить компоновщик IAR удалять дубликаты const-объектов:

__ro_placement int const volatile array[] = {1,2};

И будет только одна копия во флешь. Доступ будет немного медленнее, чем в варианте с дубликатами.

Но таким образом можно даже большие массивы объявлять/определять в .h-файлах без дублей.

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

18 часов назад, rkit сказал:

Размещением в памяти занимается линкер, а не компилятор. И не размещать несколько копий одного и того же не является проблемой на этом этапе. Хотя не знаю, что там происходит на самом деле.

Выделением памяти занимается компилятор — именно он решает, что (какие объекты) и как (в каких секциях) размещать в ней. Линкер лишь потом компонует это всё (мапит объектные секции на физические сегменты) и разрешает связи (подставляет реальные адреса в "плейсхолдеры). 

 

Если вы напишете в заголовочном файле (С++)

 

// header1.h

const int x = 5;

и потом будете ссылаться на этот константный объект любым способом, кроме случаев, где потребуется адрес, то любой современный вменяемый компилятор просто не размещает этот объект в памяти и использует только его значение — это становится возможным именно благодаря внутреннему связыванию констант в С++. И линкер тут ничего уже "размещать" не сможет, ибо нечего. Создание (размещение) объектов в памяти "не его ума дело". Да, некоторые современные линкеры достаточно интеллектуальны, чтобы производить достаточно сложную доводку финального образа (например, LTO), но существа дела это не меняет: появится (разместится в памяти) объект или не появится, решает не линкер, а компилятор.

15 часов назад, jcxz сказал:

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

6 часов назад, dxp сказал:

Если объект (массив) будет размещён в памяти, то разницы по скорости доступа не будет, и, следовательно, толку от дубликатов по скорости никакого нет.

Серьёзно? Всё теоретизируете?  :wink:

Пример из практики (IAR). 1-й случай: Массив tJSUri - в виде нескольких копий (по одной на каждую единицу компиляции):

   LogCR(COL_GREEN ">>> " COL_PURPLE "JSON in. " COL_BLUE "%s", tJSUri[jmemArg]);  
0x.... 0x....      ADR.W    R0,tJSUri                                              
0x78E1             LDRB     R1,[R4, #+3]                                           
0xF850 0x1021      LDR      R1,[R0, R1, LSL #+2]                                   
0x.... 0x....      ADR.W    R0,?_15                                                
0x.... 0x....      BL       _Z12ServiceLogCRPKcz

2-й случай: Тот же самый участок исходника, но массив tJSUri - в виде одной копии (единый на все единицы компиляции):

   LogCR(COL_GREEN ">>> " COL_PURPLE "JSON in. " COL_BLUE "%s", tJSUri[jmemArg]);  
0x.... 0x....      LDR.W    R0,??DataTable86_20                                    
0x78E1             LDRB     R1,[R4, #+3]                                           
0xF850 0x1021      LDR      R1,[R0, R1, LSL #+2]                                   
0x.... 0x....      ADR.W    R0,?_11                                                
0x.... 0x....      BL       _Z12ServiceLogCRPKcz                                   

Как видим - простое вычисление адреса относительно PC (команда ADR) заменилось на загрузку адреса по смещению к PC (LDR), что несколько медленнее.

Что и закономерно, так как компилятор не знает куда компоновщик разместит тело tJSUri, а значит не может использовать ADR, приходится использовать LDR.

 

PS: Это ещё не учитывая того, что во 2-м случае дополнительно занимается 4 байта под хранение указателя на tJSUri, который грузит LDR. Что (для мелких массивов) ещё больше снижает стоимость варианта с несколькими копиями.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 hours ago, jcxz said:

несколько медленнее

Для LogCR(), наверное, страсть как актуально.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

5 часов назад, jcxz сказал:

Серьёзно? Всё теоретизируете?  :wink:

Какая в % разница по скорости выполнения этого кода?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...