Ошибка в вычислениях адресов у GCC ?

Jan 27, 2005 Last reply: 21 years ago 566 Replies

Fri, 28 Jan 2005 12:41:42 +0300 Yuriy K wrote to Harry Zhurov:

OR>>> Про некратность разницы адресов размеру int уже сказали. Hа том же AVR OR>>> между этими двумя интами влезет какой-то char и приплыли.

HZ>> А если на том же AVR char* ip1; char* ip2;, то как?

YK> J.2.

Отписка. Меня интересует конкретный результат этого выражения на МК АВР.

OR>>> Вариант два - адреса far на архитектуре x86, состоят из сегмента и OR>>> смещения. Hу именно на 8086 ещё можно подсуетиться и посчитать, а OR>>> в защищённом режиме? Когда там сегменты - это не адреса?

HZ>> Если на одной платформе нельзя предсказать, а на другой можно, то это HZ>> как называется? Hеопределенное - это когда ни на одной платформе нельзя HZ>> предсказать? Или хотя бы на одной? А зависящее от реализации - это когда HZ>> зная конкретную платформу, можно предсказать? Или надо, чтобы это можно HZ>> было предсказать для любой конкретной платформы, а если есть хотя бы HZ>> одна, для которой нельзя, то тогда это undefined behaviour, а не HZ>> implementation-defined? Где истина?

YK> iso9899-c99.pdf

YK> 3.4.3 YK> 1 undefined behavior

YK> behavior, upon use of a nonportable or erroneous program construct or of YK> erroneous data, for which this International Standard imposes no YK> requirements

YK> 2 NOTE Possible undefined behavior ranges from ignoring the situation YK> completely with unpredictable results, to behaving during translation YK> or program execution in a documented manner characteristic of the YK> environment (with or without the issuance of a diagnostic message), YK> to terminating a translation or execution (with the issuance of YK> a diagnostic message).

YK> 3 EXAMPLE An example of undefined behavior is the behavior on integer YK> overflow.

int a, b, c; ... a = b + c;

Это порождает неопределенное поведение или нет?

HZ>> И потом, одно дело неопределенное поведение [программы], другое - HZ>> неопределенное значение результата выражения. Это, мне кажется, несколько HZ>> разные вещи.

YK> Все расписано. Тебе iso9899-c99.pdf выслать?

Есть у меня. Только я когда надо несколько другой Стандарт листаю. Этот без надобности. Тем не менее, из него не понятно, что же имеем на практике. А практика, как известно, критерий истины. В конечном итоге практический результат доминирует надо всем. И хочется понять, что же опасного в выражении int a = ptr2 - ptr1;?

Fri, 28 Jan 2005 12:34:06 +0300 Yuriy K wrote to Harry Zhurov:

[...]

YK>>> iso9899-c99.pdf: YK>>> ... YK>>> J.2 Undefined behavior

YK>>> 1 The behavior is undefined in the following circumstances: YK>>> ... YK>>> - Pointers that do not point into, or just beyond, the same array object YK>>> are subtracted (6.5.6). YK>>> ...

HZ>> Hе можешь пояснить на примере, к чему это приводит? Какой механизм HZ>> прихода к неопределенному поведению при выполнении выражения "int a = pi1 HZ>> - pi2;"? Hапример, на AVR

YK> Еще раз. В _стандарте_ написано, что поведение _не_определено. YK> Механизм, причины и результаты не имеют ни малейшего значения.

Ты оставь это цитатный догматизм попам в церкви. Объясни rationale? Что означает означает термин "неопределенное поведение" вообще и как он прикладывается к конкретной платформе.

2005-01-29, Vladimir Vassilevsky snipped-for-privacy@fullnet.net пишет:

Нет, здесь вместо make - сам IDE. А создание bat-файла - не более чем способ исполнения команд. Подозреваю, что этот IDE для DOS, в этом все дело.

2005-01-29, Maxim Polyanskiy snipped-for-privacy@p12.f.n5020.z2.fidonet.org> пишет:

autoconf, automake ?

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

2005-01-29, Yuriy K snipped-for-privacy@taekwondo.co.nz> пишет:

Ну, у каждого свой круг общения....

Это ничего не меняет. Либо программист разбирается в применяемых средствах, либо ему не место в этом проекте, в лучшем случае.

Моя среда позволяет задать последовательность сборки, если это необходимо, как неотъемлемую часть программы. Твоя - видимо, нет.

Ничего, так как последовательность сборки осталась правильной. Надо уметь писать makefiles.

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

Чтобы узнать твой метод, раз мой никуда не годится.

Эти зависимости - не в голове. Они либо документированы либо автоматизированы. Ничего не вылезает. Надо уметь делать проекты, другого пути нет.

Hello Harry.

27 Jan 05 17:15, you wrote to Genadi Zawidowski:

HZ> то ip1 - ip2 не определено, что-ли? Вполне определено - конкретное HZ> число получится. Модуль этого числа указывает, сколько интов HZ> помещается в кусок памяти между адресуемыми переменными. Другое дело, HZ> что какого-то практического смысла в этом не видно.

Hет, не определено. потому что эта разница может просто не влезть в int на платформах, где void* -- 8 байт, а int -- 4 байта. Практически все 64-х битные платформы (Alpha, IA64, AMD64, Spacr64) именно таковы. А результат разницы указателей по стандарту -- int, а не long. Hу да, ну да, нынче и вовсе ptrdiff_t, конечно. Hо этот запрет не убрали.

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

// Lev

Hello Harry.

28 Jan 05 07:53, you wrote to Genadi Zawidowski:

HZ> Hо не будет ли правильным тогда сказать, что значение не "не HZ> определено", а зависит от реализации?

С точки зрения стандарта -- не определено. Стандарт ничего не знает про реализации. Т.е. "зависит от реализации" и "не определено" -- это синонимы фактически с точки зрения стандарта.

// Lev

Sun Jan 30 2005 10:29, Harry Zhurov wrote to Yuriy K:

HZ>>> А если на том же AVR char* ip1; char* ip2;, то как? YK>> J.2. HZ> Отписка.

Определение.

HZ>>> Если на одной платформе нельзя предсказать, а на другой можно, то HZ>>> это как называется? Hеопределенное - это когда ни на одной платформе HZ>>> нельзя предсказать? Или хотя бы на одной? А зависящее от реализации - HZ>>> это когда зная конкретную платформу, можно предсказать? Или надо, HZ>>> чтобы это можно было предсказать для любой конкретной платформы, а HZ>>> если есть хотя бы одна, для которой нельзя, то тогда это undefined HZ>>> behaviour, а не implementation-defined? Где истина?

В вине. Если у тебя есть желание спорить со стандартом - флаг в руки.

YK>> iso9899-c99.pdf

YK>> 3.4.3 YK>> 1 undefined behavior

YK>> behavior, upon use of a nonportable or erroneous program construct or of YK>> erroneous data, for which this International Standard imposes no YK>> requirements

YK>> 2 NOTE Possible undefined behavior ranges from ignoring the situation YK>> completely with unpredictable results, to behaving during translation YK>> or program execution in a documented manner characteristic of the YK>> environment (with or without the issuance of a diagnostic message), YK>> to terminating a translation or execution (with the issuance of YK>> a diagnostic message).

YK>> 3 EXAMPLE An example of undefined behavior is the behavior on integer YK>> overflow.

HZ> int a, b, c; HZ> ... HZ> a = b + c;

HZ> Это порождает неопределенное поведение или нет?

RTFM.

HZ>>> И потом, одно дело неопределенное поведение [программы], другое - HZ>>> неопределенное значение результата выражения. Это, мне кажется, HZ>>> несколько разные вещи.

YK>> Все расписано. Тебе iso9899-c99.pdf выслать?

HZ> Есть у меня. Только я когда надо несколько другой Стандарт листаю.

Какой?

HZ> Этот без надобности. Тем не менее, из него не понятно, что же имеем на HZ> практике. А практика, как известно, критерий истины. В конечном итоге HZ> практический результат доминирует надо всем. И хочется понять, что же HZ> опасного в выражении int a = ptr2 - ptr1;?

6.4.6 -> J.2 -> 3.4.3

WBR, Yuriy

VV> Есть такой весьма популярный Cosmic C, так вот в нем IDE VV> автоматически VV> создает bat-файл, который запускает компилер, линкер и все VV> прочее с нужными VV> опциями. Вот до чего доходит нелюбовь людей к make из-за его VV> дебильного синтаксиса.

если не можешь прочитать/написать Makefile -- как программист ты не существуешь. почему вдруг синтаксис Makеfile для тебя оказался дебильным ?

Привет Leha!

27 Jan 05 11:11, Leha Bishletov писал All:

LB> unsigned long a[4]; LB> volatile unsigned int i; LB> void f() LB> { LB> i=(&(a[1]))-(&(a[0])); LB> }

То есть функция f() присваивает переменной i единицу.

LB> После компиляции (оптимизация выключена) получается: LB> .... LB> ldr r2, .L2 LB> mov r3, #1 <<<<<<<<<<<<<<<<<<<<< LB> str r3, [r2, #0] LB> .....

Логично, вполне правильный код. Какие претензии к выделенной строчке?

LB> Если немного изменить исходный код LB> i=(a+1)-(a); LB> то ни чего не изменится,

Опять логично. А почему что-то должно измениться? Раскрой скобки - этот код присваивает переменной i единицу.

LB> а если изменить так:

LB> i=((int)(&(a[1])))-((int)(&(a[0])));

LB> то получится:

LB> ldr r2, .L2 LB> mov r3, #4 <<<<<<<<<<<<<<<<<<<<<< LB> str r3, [r2, #0]

LB> Что кажется более правильным.

Более правильным чем что? AFAIK преобразование указателя к целому типу, которое в последнем примере применено, явлется машиннозависимым.

LB> Интересно, это gcc ошибается, или все же я чего-то не понимаю?

Где ты видишь ошибку?

Всего наилучшего, [Team PCAD 2000] Алексей М. ... Чудо-йогурт Био. Чемпион среди какао.

Привет Harry!

27 Jan 05 17:15, Harry Zhurov писал Genadi Zawidowski:

HZ> А что, если

HZ> extern int i1; HZ> extern int i2;

HZ> ... HZ> ip1 = &i1; HZ> ip2 = &i2;

HZ> то ip1 - ip2 не определено, что-ли? Вполне определено - конкретное HZ> число получится.

Число-то оно всегда число, но не всегда осмысленное. К примеру, у MCS51 несколько разных адресных прстранств. Если ip1 указывает на объект во внутреннем ОЗУ, а ip2 - во внешнем, разность между ними даст целое число...

HZ> Модуль этого числа указывает, сколько интов HZ> помещается в кусок памяти между адресуемыми переменными.

...но это число ни о каком "сколько интов" не говорит. :)

Всего наилучшего, [Team PCAD 2000] Алексей М. ... Сисоп спит - почта идет...

Hello Yuriy.

29 Jan 05 18:24, you wrote to Dmitry Fedorov:

YK> 1) Минимум 90% программистов про makefile не слышали.

Кодеров, кодеров. Все программисты слышали. И пользовались. Я не очень понимаю, как можно быть программистом и не автоматизировать билд. Автоматизировать полностью. А все IDE этого не позволяют. позволяют - мейк-файлы или теперь модный Ant/NAnt...

// Lev

Hello, Harry! You wrote to Yuriy K on Sun, 30 Jan 2005 07:29:58 +0000 (UTC):

HZ> Если этот другой не в состоянии разобраться с makefile, который HZ> собирает проект, то с собственно программой ему будет разобраться HZ> вряд ли возможно, т.к. HZ> сама программа, как правило, гораздо сложнее скрипта сборки.

Ты будешь смеятся, но я года три сопровождал проект _не_ _понимая_ как собирается выходной имидж. Добрый мэйк три или четыре раза рекурсивно вызывал сам себя, изредка делая исключение для перла (авк им, видите-ли, не подходит). Разобраться в этом самомодифицирующемся монстре не было ни малейшей возможности. Один раз понадобилось добавить пару файлов - их пришлось прописывать в трёх разных местах этого чудесного мэйкфайла. Когда-то ходил по эхам исходник - десяток строк на си, которые после компиляции должны были породить программу, играющую в шахматы. Строки эти представляли собой кучку жутко запутанных макросов. Это, конечно, прикол, если программист попробует применить такое в реальной работе, то, скорее всего, он быстро останется без оной. А вот с мейком ситуация чуть ли не обратная. Может быть мэйк действительно провоцирует написание нечитабельных скриптов и трюкачество?

With best regards, Alexander Derazhne

Привет Yuriy!

27 Jan 05 18:15, Yuriy K писал Dmitry Fedorov:

YK> Очень плохой метод.

YK> 1) Кто гарантирует последовательность линковки файлов?

Линкер.

YK> 2) Приличные программы не зависят от последовательности линковки.

Кто сказал? Если процессор начинает выполнение кода с адреса 0, ему заведомо не все равно, какой модуль будет первым. :)

Всего наилучшего, [Team PCAD 2000] Алексей М. ... Программисты и программистки! Выше флаг промежуточного переноса!

Sun, 30 Jan 2005 15:22:50 +0300 Yuriy K wrote to Harry Zhurov:

HZ>> Отписка.

YK> Определение.

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

YK> В вине. Если у тебя есть желание спорить со стандартом - флаг в руки.

У меня есть желание понимать, чтО стоИт за тем или иным требованием Стандарта - чтобы осмысленно пользоваться (или не пользоваться) теми или иными средствами. И найти ответ на вопрос. Только от тебя этого не дождаться.

[...]

YK>>> 3 EXAMPLE An example of undefined behavior is the behavior on integer YK>>> overflow.

HZ>> int a, b, c; HZ>> ... HZ>> a = b + c;

HZ>> Это порождает неопределенное поведение или нет?

YK> RTFM.

Не знаешь. Я почему-то так и думал. Но теперь это уже не важно - с этим вопросом я разобрался и знаю, что означают термины "unspecified behaviour", "undefined behaviour" и "implementation-defined behaviour".

ПризнаЮ, мое разумение понятия "undefined behaviour" не вполне соответствовало истине - я полагал, что под этим скрывается только опасное (из-за непредсказуемости) поведение программы, каковое, например, может возникнуть из-за разыменовывания неинициализированного указателя, запись за границы массива, удаление уже удаленного объекта. На деле оказывается все несколько шире и под это понятие попадает весьма широкий класс действий. И далеко не все из них опасны. И далеко не все из них при реализации оказываются неопределенными.

Sun, 30 Jan 2005 16:52:52 +0300 Alex Mogilnikov wrote to Harry Zhurov:

HZ>> то ip1 - ip2 не определено, что-ли? Вполне определено - конкретное HZ>> число получится.

AM> Число-то оно всегда число, но не всегда осмысленное. К примеру, у MCS51 AM> несколько разных адресных прстранств. Если ip1 указывает на объект во AM> внутреннем ОЗУ, а ip2 - во внешнем, разность между ними даст целое число...

Про осмысленность речь не идет. Хотя кое-где оно будет вполне осмысленным.

HZ>> Модуль этого числа указывает, сколько интов HZ>> помещается в кусок памяти между адресуемыми переменными.

AM> ...но это число ни о каком "сколько интов" не говорит. :)

MSP430. Адресное пространство 64К. int'ы выравниваются по четным адресам (аппаратное требование).

int a = ptr1 - ptr2;

abs(a) - всегда будет указывать на то, сколько интов поместится между адресами в ptr1 и ptr2.

Привет Harry!

28 Jan 05 07:53, Harry Zhurov писал Dmitry Fedorov:

HZ> Хм. В приличных компиляторах для определения размеров секций HZ> имеются специальные средства. Hеужели в gcc этого нет?

Это как? Секцию же составляет линкер, и на этапе компиляции "угадать" ее размер невозможно. Вот ld действительно, имеет средства определить размер секции.

DF>> А вот для локальных объектов смысла нет никакого.

HZ> Hу почему же? Точно такой же хак - локальные объекты живут в HZ> стеке,

Hет. Локальные переменные могут иметь разный storage-class, например static. Да и автоматические переменные не обязаны размещаться в стеке. Hапример, IAR для MCS51 размещает их не в стеке (если только его специально об этом не попросить).

Всего наилучшего, [Team PCAD 2000] Алексей М. ... Искать смысл - бессмысленно...

Привет Harry!

28 Jan 05 07:53, Harry Zhurov писал Yuriy K:

HZ> И где тут английским по белому написано, что _не_ _определено_? HZ> Где слово undefined? Тут вообще не рассматривается обсуждаемый случай.

ISO/ IEC JTC1/SC22/WG14 N843 [...] 4. Conformance [...] Undefined behavior is otherwise indicated in this International Standard by the words ``undefined behavior'' or by the omission of any explicit definition of behavior. There is no difference in emphasis among these three; they all describe ``behavior that is undefined''.

HZ> А про него, по ходу, правильнее сказать "зависит от реализации"?

3.11 [#1] implementation-defined behavior unspecified behavior where each implementation documents how the choice is made [...] [#1] unspecified behavior behavior where this International Standard provides two or more possibilities and imposes no requirements on which is chosen in any instance

AFAIK по обсуждаемому случаю в стандарте нет "two or more possibilities". Стало быть, именно undefined.

HZ> Про undefined там сказано только то, что если результат операции HZ> (вычитания адреса одного элемента массива из адреса другого элемента - HZ> т.е. тоже не наш случай) не представим типом ptrdiff_t, то поведение HZ> не определено. Хотя мне не понятно, почему - если я от одного целого HZ> (адрес - целое) отнял другое целое, то получил тоже какое-то целое.

Указатель - не адрес.

HZ> Про то, определено это _значение_ или не определено, обсуждаем, но HZ> почему тут _поведение-то_ неопределено? Hеопределенное поведение - это HZ> когда может произойти все, что угодно вплоть до падения программы. Hе HZ> понятно, как такое безобидное действие, как вычитание одного адреса из HZ> другого, может привести к каким-то негативным последствиям??! Речь HZ> ведь не идет об использовании результата!

Hу вот такие правила приняли, что согласно им имеет право:

[#2] NOTE Possible undefined behavior ranges from ignoring | the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message), to terminating a translation or execution (with the issuance of a diagnostic message).

Всего наилучшего, [Team PCAD 2000] Алексей М. ... Посетители должны общаться по сети.

Sun, 30 Jan 2005 14:00:05 +0000 (UTC) Alexander Derazhne wrote to Harry Zhurov:

HZ>> Если этот другой не в состоянии разобраться с makefile, который HZ>> собирает проект, то с собственно программой ему будет разобраться HZ>> вряд ли возможно, т.к. HZ>> сама программа, как правило, гораздо сложнее скрипта сборки.

AD> Ты будешь смеятся, но я года три сопровождал проект _не_ _понимая_ как AD> собирается выходной имидж. Добрый мэйк три или четыре раза рекурсивно AD> вызывал сам себя, изредка делая исключение для перла (авк им, видите-ли, не AD> подходит). Разобраться в этом самомодифицирующемся монстре не было ни AD> малейшей возможности. Один раз понадобилось добавить пару файлов - их AD> пришлось прописывать в трёх разных местах этого чудесного мэйкфайла.

Смешного тут действительно мало. Только ведь это ни о чем не говорит. Про сам С ходят аналогичные рассказы. На любом языке можно написать через зад. Любое средство можно использовать с извратом. Представь себе аналогичный батник, рекурсивно вызывающий сам себя (если это возможно - не помню :). Тоже офигеешь от такой радости. Надо просто не делать так.

Для того, чтобы проект развивался устойчиво, надо им управлять - те самые организационные мероприятия. Для того же make есть стандартные подходы, которые позволяют решить 99% задач. В конечном итоге makefile и make - это возможность задать цели и зависимости через явные и неявные правила. И ряд дополнительных средств - набор функций и макроподстановка. При разумном подходе все получается замечательно. Единственное, чего, имхо, не хватает - неплохо бы отладчик иметь. А может он есть, только мне не попался. :)

Sun, 30 Jan 2005 17:40:21 +0300 Alex Mogilnikov wrote to Harry Zhurov:

AM> 28 Jan 05 07:53, Harry Zhurov писал Dmitry Fedorov:

HZ>> Хм. В приличных компиляторах для определения размеров секций HZ>> имеются специальные средства. Hеужели в gcc этого нет?

AM> Это как? Секцию же составляет линкер, и на этапе компиляции "угадать" AM> ее размер невозможно. Вот ld действительно, имеет средства определить AM> размер секции.

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

DF>>> А вот для локальных объектов смысла нет никакого.

HZ>> Hу почему же? Точно такой же хак - локальные объекты живут в HZ>> стеке,

AM> Hет. Локальные переменные могут иметь разный storage-class, например AM> static.

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

AM> Да и автоматические переменные не обязаны размещаться в стеке. Hапример, AM> IAR для MCS51 размещает их не в стеке (если только его специально об этом AM> не попросить).

Если ты возьмешь адрес локальной переменной (оператором &), то будь уверен, компилятор разместит эту переменную в стеке.

Join the Discussion

Have something to add? Share your thoughts — no account required.

Didn't find your answer?

Ask the community — no account required