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

Hello, All!

Работаю с GCC для ARM и обнаружил одну странность. Вот исходный код:

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

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

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

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

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

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

Что кажется более правильным. Интересно, это gcc ошибается, или все же я чего-то не понимаю?

With best regards, Leha Bishletov. E-mail: snipped-for-privacy@rol.ru

Reply to
Leha Bishletov
Loading thread data ...

Thu Jan 27 2005 11:11, Leha Bishletov wrote to All:

LB> i=(&(a[1]))-(&(a[0])); LB> i=(a+1)-(a); LB> то ни чего не изменится, а если изменить так:

по стандарту - количество элементов между двумя указателями

LB> i=((int)(&(a[1])))-((int)(&(a[0]))); LB> то получится:

разница между значениями адресов. Компилятор все нормально делает.

Генка на сервере pochtamt.ru в ящике mgs2001

Reply to
Genadi Zawidowski

Привет, Genadi! Вы писали to Leha Bishletov on Thu, 27 Jan 2005 13:03:52 +0300:

LB>> i=(&(a[1]))-(&(a[0])); LB>> i=(a+1)-(a); GZ> по стандарту - количество элементов между двумя указателями

Честно говоря, не знал. А как по стандарту трактуются такие выражения:

int a[4], *ip1, *ip2;

ip2-ip1 = ? (a+1)-ip1 = ?

With best regards, Leha Bishletov. E-mail: snipped-for-privacy@rol.ru

Reply to
Leha Bishletov

Thu Jan 27 2005 15:46, Leha Bishletov wrote to Genadi Zawidowski:

LB>>> i=(&(a[1]))-(&(a[0])); LB>>> i=(a+1)-(a); GZ>> по стандарту - количество элементов между двумя указателями

LB> Честно говоря, не знал. А как по стандарту трактуются такие выражения:

LB> int a[4], *ip1, *ip2;

LB> ip2-ip1 = ? LB> (a+1)-ip1 = ?

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

Генка на сервере pochtamt.ru в ящике mgs2001

Reply to
Genadi Zawidowski

Thu, 27 Jan 2005 16:43:04 +0300 Genadi Zawidowski wrote to Leha Bishletov:

LB>>>> i=(&(a[1]))-(&(a[0])); LB>>>> i=(a+1)-(a); GZ>>> по стандарту - количество элементов между двумя указателями

LB>> Честно говоря, не знал. А как по стандарту трактуются такие выражения:

LB>> int a[4], *ip1, *ip2;

LB>> ip2-ip1 = ? LB>> (a+1)-ip1 = ?

GZ> "по стандарту" результат таких выражений определен, если сравниваются или GZ> вычитаются адреса элементов одного массива между собой.

А что, если

extern int i1; extern int i2;

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

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

Или (может я не понял?) что имелось в виду?

Reply to
Harry Zhurov

Thu Jan 27 2005 17:15, Harry Zhurov wrote to Genadi Zawidowski:

LB>>> Честно говоря, не знал. А как по стандарту трактуются такие выражения:

LB>>> int a[4], *ip1, *ip2;

LB>>> ip2-ip1 = ? LB>>> (a+1)-ip1 = ?

GZ>> "по стандарту" результат таких выражений определен, если сравниваются GZ>> или вычитаются адреса элементов одного массива между собой.

HZ> А что, если

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

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

HZ> то ip1 - ip2 не определено, что-ли?

Hе определено.

iso9899-c99.pdf: ...

6.5.6 Additive operators ... 9 When two pointers are subtracted, both shall point to elements of the same array object, or one past the last element of the array object; the result is the difference of the subscripts of the two array elements. ...

WBR, Yuriy.

Reply to
Yuriy K
2005-01-27, Harry Zhurov snipped-for-privacy@online.nsk.su> пишет:

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

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

Reply to
Dmitry Fedorov
2005-01-27, Yuriy K snipped-for-privacy@taekwondo.co.nz> пишет:

А члены структуры?

Reply to
Dmitry Fedorov

Thu Jan 27 2005 17:45, Dmitry Fedorov wrote to Harry Zhurov:

DF> Для глобальных символов смысл есть. Пару глобальных символов размещают в DF> одной секции в первом и последнем объектных файлах и получают в DF> программе возможность определить размер секции и что такой-то объект DF> входит в эту секцию. При этом - никакого ассемблера (с GNU расширениями).

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

1) Кто гарантирует последовательность линковки файлов? 2) Приличные программы не зависят от последовательности линковки. Для управления размещением в памяти есть более другие методы.

WBR, Yuriy.

Reply to
Yuriy K

Thu Jan 27 2005 18:00, Dmitry Fedorov wrote to Yuriy K:

DF> From: Dmitry Fedorov snipped-for-privacy@inp.nsk.su>

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

DF> А члены структуры?

Hе определено.

Английским по белому :) написано, что вычитать можно только элементы одного массива.

WBR, Yuriy.

Reply to
Yuriy K

Thu Jan 27 2005 17:15, Harry Zhurov wrote to Genadi Zawidowski:

HZ> From: "Harry Zhurov" snipped-for-privacy@online.nsk.su>

HZ> Thu, 27 Jan 2005 16:43:04 +0300 Genadi Zawidowski wrote to Leha HZ> Bishletov:

LB>>>>> i=(&(a[1]))-(&(a[0])); LB>>>>> i=(a+1)-(a); GZ>>>> по стандарту - количество элементов между двумя указателями

LB>>> Честно говоря, не знал. А как по стандарту трактуются такие выражения:

LB>>> int a[4], *ip1, *ip2;

LB>>> ip2-ip1 = ? LB>>> (a+1)-ip1 = ?

GZ>> "по стандарту" результат таких выражений определен, если сравниваются GZ>> или вычитаются адреса элементов одного массива между собой.

HZ> А что, если

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

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

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

Hу не на всех архитектурах линкер будет инты выравнивать на их размер... представь себе, между ними будет некратное число... остаток от деления... Правильно, сравнивать два таких адреса смысла нет. А разработчиков компилятра этот пункт избавляет от необходимости правильно обрабатывать такие случаи. Да, там еще специально оговаривается, что допустимо использовать в таких вычислениях адрес сразу за последним элементом.

int a[10]; int d = a [10] - a[5]; assert(d == 5);

Этот код правильный. А если изменить на

int d = a [11] - a[5];

то уже нет.

Генка на сервере pochtamt.ru в ящике mgs2001

Reply to
Genadi Zawidowski
2005-01-27, Yuriy K snipped-for-privacy@taekwondo.co.nz> пишет:

Makefile

В таком случае, все программы, собираемые GNU ld - неприличные, ибо успешность сборки зависит от правильной последовательности объектных файлов и библиотек.

Приличный Makefile - часть любой приличной программы.

Какие?

Кстати, символы начала/конца секций кода и данных, определены в этих стандартах.

Reply to
Dmitry Fedorov

Привет, Genadi! Вы писали to Leha Bishletov on Thu, 27 Jan 2005 16:43:04 +0300:

Можно еще спросить про поведение по "стандарту"?

union { Type1 var1; struct {Type1 var1; Type2 var2; ...} s; .... } u;

Можно ли быть уверенным, что u.var1==u.s.var1?

With best regards, Leha Bishletov. E-mail: snipped-for-privacy@rol.ru

Reply to
Leha Bishletov

Thu Jan 27 2005 18:46, Dmitry Fedorov wrote to Yuriy K:

DF> Makefile

Кто создает makefile?

DF> В таком случае, все программы, собираемые GNU ld - неприличные, DF> ибо успешность сборки зависит от правильной последовательности DF> объектных файлов и библиотек.

Дык. Глюкодром и ламерство.

DF> Приличный Makefile - часть любой приличной программы.

DF> Какие?

Section(segment). Совершенно стандартный механизм.

WBR, Yuriy.

Reply to
Yuriy K

Hello, Leha Bishletov ! > Работаю с GCC для ARM и обнаружил одну странность. Вот исходный > код:

Ты забыл, что в С массив и указатель - одно и тоже, и что при адресной арифметике в качестве единицы используется размер типа. Потому GCC все делает правильно, а если тебе нужно получить 4, пиши sizeof long.

С уважением, Дима Орлов.

Reply to
Dima Orlov

Hello, Harry Zhurov !

Hе определено в том смысле, что ты не можешь заранее на произвольном компиляторе сказать чему оно равно.

Что значит конкретное?

С уважением, Дима Орлов.

Reply to
Dima Orlov

Thu, 27 Jan 2005 20:37:00 +0300 Dima Orlov wrote to Leha Bishletov:

DO> Ты забыл, что в С массив и указатель - одно и тоже,

В С массив и указатель - _НЕ_ одно и то же! Единственное, что их связывает - это то, что имя массива автоматически преобразовывается к указателю на первый элемент массива в выражениях, где ожидается указатель, что позволяет, например, при вызове функции, принимающей указатель, указывать просто имя массива - преобразование этого имени в адрес первого элемента будет проделано автоматически. Ну, и еще для указателей допустим синтаксис обращения к массиву:

int Array[N]; int* p = Array;

int a = Array[3]; int b = p[3];

a и b - получат одно и то же значение 4-го элемента массива. Но это ни в коем случае не означает, что p и Array одно и то же. Указатель - это адрес в памяти. Массив - это агрегатный тип/объект, состоящий из объектов одинакового типа. Разница очевидна. Она хотя бы в том, что при объявлении массива происходит выделение памяти под него, т.ч. всегда можно написать:

int Array[N];

Array[3] = 5;

но если написать:

int* p;

p[3] = 5;

то получишь, afair, неопределенное поведение.

Reply to
Harry Zhurov

Thu, 27 Jan 2005 18:36:35 +0300 Genadi Zawidowski wrote to Harry Zhurov:

[...]

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

GZ> Hу не на всех архитектурах линкер будет инты выравнивать на их размер... GZ> представь себе, между ними будет некратное число... остаток от деления...

Но не будет ли правильным тогда сказать, что значение не "не определено", а зависит от реализации? Для конкретной реализации всегда можно сказать, что там получится.

GZ> Правильно, сравнивать два таких адреса смысла нет.

Про смысл понятно, с этим не спорю. Хотя для хаков вполне может сгодиться. :)

Reply to
Harry Zhurov

Thu, 27 Jan 2005 14:45:09 +0000 (UTC) Dmitry Fedorov wrote to Harry Zhurov:

[...]

DF> Для глобальных символов смысл есть. Пару глобальных символов размещают в DF> одной секции в первом и последнем объектных файлах и получают в DF> программе возможность определить размер секции и что такой-то объект DF> входит в эту секцию. При этом - никакого ассемблера (с GNU расширениями).

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

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

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

Reply to
Harry Zhurov

Thu, 27 Jan 2005 17:43:41 +0300 Yuriy K wrote to Harry Zhurov:

[...]

GZ>>> "по стандарту" результат таких выражений определен, если сравниваются GZ>>> или вычитаются адреса элементов одного массива между собой.

HZ>> А что, если

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

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

HZ>> то ip1 - ip2 не определено, что-ли?

YK> Hе определено.

YK> iso9899-c99.pdf: YK> ... YK> 6.5.6 Additive operators YK> ... YK> 9 When two pointers are subtracted, both shall point to elements of the YK> same array object, or one past the last element of the array object; YK> the result is the difference of the subscripts of the two array elements. YK> ...

И где тут английским по белому написано, что _не_ _определено_? Где слово undefined? Тут вообще не рассматривается обсуждаемый случай. А про него, по ходу, правильнее сказать "зависит от реализации"? Тем более, что так и есть. Про смысл и полезность этого уже сказано.

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

Reply to
Harry Zhurov

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.