_W>Как будет работать этот код на компиляторе с 64-битными указателями и 32-битным int ?
Это undefined behavior, разумеется. Как оно будет проявляться в Вашей гипотетической реализации, предсказать нельзя. Никто ведь не знает, как этот 64-разрядный указатель устроен. Возможно, в нем 32 разряда – селектор, а 32 – смещение внутри сегмента; только над последним и выполняется адресная арифметика. Тогда Вы опять никаких внешних проявлений неопределенного поведения не увидите.
_W>Как будет работать этот код на компиляторе с 64-битными указателями и 32-битным int ?
Плохо будет работать. Внутри f имеем преобразование типа i от unsigned к ptrdiff_t. Так как в данном случае ptrdiff_t вообще не является одним из целочисленных типов, описанных в Стандарте языка, то уже только из этого следует "правовая неопределенность" в данном преобразовании. Если же на данное преобразование распространяются положения §4.7(3) Стандарта, то тем более — получим значение типа ptrdiff_t, равное в данном случае ((ptrdiff_t(1) << 32) — 10) (то есть большое положительное число).
Я кончил, джентльмены, мне остается только поблагодарить вас за внимание.
> _W>Как будет работать этот код на компиляторе с 64-битными указателями и 32-битным int ? > > Это undefined behavior, разумеется. Как оно будет проявляться в Вашей гипотетической реализации, предсказать нельзя. Никто ведь не знает, как этот 64-разрядный указатель устроен. Возможно, в нем 32 разряда – селектор, а 32 – смещение внутри сегмента; только над последним и выполняется адресная арифметика. Тогда Вы опять никаких внешних проявлений неопределенного поведения не увидите.
A>Плохо будет работать. Внутри f имеем преобразование типа i от unsigned к ptrdiff_t. Так как в данном случае ptrdiff_t вообще не является одним из целочисленных типов, описанных в Стандарте языка, то уже только из этого следует "правовая неопределенность" в данном преобразовании. Если же на данное преобразование распространяются положения §4.7(3) Стандарта, то тем более — получим значение типа ptrdiff_t, равное в данном случае ((ptrdiff_t(1) << 32) — 10) (то есть большое положительное число).
Вообще-то сейчас перечитал 5.7(5), ptrdiff_t там не упоминается (для меня это стало откровением ). Ну что ж, значит к указателю прибавится целочисленное значение типа unsigned, то есть большое положительное число. Ничего в принципе не меняется.
Я кончил, джентльмены, мне остается только поблагодарить вас за внимание.
> _W>Как будет работать этот код на компиляторе с 64-битными указателями и 32-битным int ? > > Это undefined behavior, разумеется. Как оно будет проявляться в Вашей гипотетической реализации, предсказать нельзя. Никто ведь не знает, как этот 64-разрядный указатель устроен. Возможно, в нем 32 разряда – селектор, а 32 – смещение внутри сегмента; только над последним и выполняется адресная арифметика.
Даже если это и будет так, то на адресной арифметике C++ это никак не отразится.
Пример: 32 битный указатель на x86 виндозе и линуксе есть не что иное как 10-bit индекс в каталоге (1024 записи) таблиц страниц + 10-bit индекс в таблице (1024 записи) страниц + 12 бит смещение (0 — 4kb) на странице. И этот указатель представлен в C++ как собственное реальное значение, который мы можем инкрементировать и т.д..
Здравствуйте, achp, Вы писали:
A>>Плохо будет работать. Внутри f имеем преобразование типа i от unsigned к ptrdiff_t. Так как в данном случае ptrdiff_t вообще не является одним из целочисленных типов, описанных в Стандарте языка, то уже только из этого следует "правовая неопределенность" в данном преобразовании. Если же на данное преобразование распространяются положения §4.7(3) Стандарта, то тем более — получим значение типа ptrdiff_t, равное в данном случае ((ptrdiff_t(1) << 32) — 10) (то есть большое положительное число).
A>Вообще-то сейчас перечитал 5.7(5), ptrdiff_t там не упоминается (для меня это стало откровением ). Ну что ж, значит к указателю прибавится целочисленное значение типа unsigned, то есть большое положительное число. Ничего в принципе не меняется.
Всё упирается в вопрос: а какой размер у (unsigned) int?
При вызове f(..., -10) мы имеем int -> unsigned int, получаем большое положительное число. Об этом, кстати, должен сообщить компилятор варнингом.
Внутри функции unsigned -> ptrdiff_t.
Если его разрядность меньше (что вряд ли) или равна разрядности int, то получим такое же число со знаком.
Если же больше — то опаньки.
Пример ситуации, где sizeof(ptrdiff_t) > sizeof(int) — на 16-битном x86, модель памяти huge.
Здравствуйте, Кодт, Вы писали:
К>Всё упирается в вопрос: а какой размер у (unsigned) int?
Насколько я понимаю, вопрос задается применительно к платформе IA64.
A>>Вообще-то сейчас перечитал 5.7(5), ptrdiff_t там не упоминается (для меня это стало откровением ). Ну что ж, значит к указателю прибавится целочисленное значение типа unsigned, то есть большое положительное число. Ничего в принципе не меняется.
К>Внутри функции unsigned -> ptrdiff_t.
Я тоже так сначала подумал, но, перечитав 5.7(5), не увидел там упоминания ptrdiff_t. Значит, целое должно рассматриваться в соответствии со своим типом. unsigned(-10) — это большое положительное целое.
Значит, имеем неопределенное поведение.
Кстати, формально неопределенное поведение в приведенном куске кода есть вне зависимости от размеров типов.
Я кончил, джентльмены, мне остается только поблагодарить вас за внимание.
_W>Как будет работать этот код на компиляторе с 64-битными указателями и 32-битным int ?
_W>Любопытсво чисто праздное, просто интересно.
зависит от того, какого размера у тебя array.
если указатель array+20, смещенный на это огромное число (unsigned)-10, все равно будет указывать внутрь array — нет проблем.
Здравствуйте, jazzer, Вы писали:
J>зависит от того, какого размера у тебя array. J>если указатель array+20, смещенный на это огромное число (unsigned)-10, все равно будет указывать внутрь array — нет проблем.
Нифига себе "нет проблем". Получим валидный, но совершенно левый указатель.
void print_nth(int* p, unsigned short o)
{ printf("%d\n", *(p+o)); }
const unsigned long L=1L<<16;
int buf[L+1];
main()
{
buf[0] = 123;
buf[L] = 456;
print_nth(buf+0,-0);
print_nth(buf+1,-1);
}
_W>Как будет работать этот код на компиляторе с 64-битными указателями и 32-битным int ? _W>Любопытсво чисто праздное, просто интересно.
А почему именно unsigned? Это принципиально? Насколько я понимаю адресную арифметику, в отрицательных смещениях нет никакого криминала (если не выходит за границы валидной области памяти). Принципиально то, что индекс должен быть знаковым, то есть, int. Для беззнакового по идее должно работать, если только sizeof(ptr) == sizeof(unsigned).
Проверил на Sun в 64-бит режиме, с int работает, с unsigned, как и предполагалось, падает
#include <stdio.h>
int f(const int* array, unsigned i) { return array[i]; }
int main()
{
int buf[100];
for(int i = 0; i < 100; i++) buf[i] = i;
buf[10] = 12345;
printf("%d\n", f(buf+20, -10));
}
Здравствуйте, achp, Вы писали:
К>>Нифига себе "нет проблем". Получим валидный, но совершенно левый указатель.
A>Это как? Он либо "валидный", либо "левый".
А вот так:
int xz() { return rand()%100; }
// int xz() { return 50; }int data[100] = { 0 };
main()
{
data[50] = 123;
printf("%d", data[xz()]); // ой! а что это за нолик? а в предыдущей версии работало как надо...
printf("%d", data[rand()]); // а здесь какое-то странное число получилось... если не AV...
}
Здравствуйте, achp, Вы писали:
A>Здравствуйте, Кодт, Вы писали:
К>>Всё упирается в вопрос: а какой размер у (unsigned) int?
A>Насколько я понимаю, вопрос задается применительно к платформе IA64.
A>>>Вообще-то сейчас перечитал 5.7(5), ptrdiff_t там не упоминается (для меня это стало откровением ). Ну что ж, значит к указателю прибавится целочисленное значение типа unsigned, то есть большое положительное число. Ничего в принципе не меняется.
К>>Внутри функции unsigned -> ptrdiff_t.
A>Я тоже так сначала подумал, но, перечитав 5.7(5), не увидел там упоминания ptrdiff_t. Значит, целое должно рассматриваться в соответствии со своим типом. unsigned(-10) — это большое положительное целое.
13.6/13 For every cv-qualified or cv-unqualified object type T there exists candidate operator functions of the form
...
T& operator[](T*, ptrdiff_t);
...
Приведение типа дожлно быть, после чего, по определению, ptr[diff] есть *(ptr + diff).
Определение типа ptrdiff_t зависит от реализации, и, строго говоря, нельзя утверждать, что оно неотрицательно.
Приведенный пример может вполне корректно работать.
Кстати, значение unsigned(-10) тоже implementation defined.
A>Значит, имеем неопределенное поведение.
A>Кстати, формально неопределенное поведение в приведенном куске кода есть вне зависимости от размеров типов.
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, jazzer, Вы писали:
J>>зависит от того, какого размера у тебя array. J>>если указатель array+20, смещенный на это огромное число (unsigned)-10, все равно будет указывать внутрь array — нет проблем.
К>Нифига себе "нет проблем". Получим валидный, но совершенно левый указатель.
Так не бывает
согласись, что размер массива в 64-битной архитектуре можно сделать больше (unsigned)-10.
И тогда действительно не будет проблем.
Мы же не знаем, какого размера у него массив и как он определяется.
а то, что ты писал про инициализированность элементов массива, согласись, к делу не относится, хотя бы потому, что мы не знаем, как он у него заполняется в реальности.
Здравствуйте, MaximE, Вы писали:
>> Это undefined behavior, разумеется. Как оно будет проявляться в Вашей гипотетической реализации, предсказать нельзя. Никто ведь не знает, как этот 64-разрядный указатель устроен. Возможно, в нем 32 разряда – селектор, а 32 – смещение внутри сегмента; только над последним и выполняется адресная арифметика.
ME>Даже если это и будет так, то на адресной арифметике C++ это никак не отразится.
Честно говоря, не понял, как это соотносится с написанным выше. Разумеется, внутреннее устройство указателя и правила обработки переполнения при адресной арифметике не отразятся на результатах корректных вычислений. Но именно от них будет зависеть наблюдаемый эффект в случае неопределенного поведения.
Здравствуйте, 0xFADE, Вы писали:
FAD>13.6/13 FAD>For every cv-qualified or cv-unqualified object type T there exists candidate operator functions of the form FAD>... FAD>T& operator[](T*, ptrdiff_t); FAD>...
Не мешало бы еще прочитать, к чему вообще относится этот раздел.
13.6/1 These candidate functions participate in the operator overload resolution process as described in 13.3.1.2 and are used for no other purpose.
FAD>Приведение типа дожлно быть, после чего, по определению, ptr[diff] есть *(ptr + diff).
Тип ptrdiff_t не имеет никакого отношения к сложению указателя с целым.
FAD>Определение типа ptrdiff_t зависит от реализации, и, строго говоря, нельзя утверждать, что оно неотрицательно.
Что значит "неотрицательно"?.. ptrdiff_t определяется как знаковый целый тип (7.1.6 в C90, 7.17/2 в C99, ср. 5.7/6 в C++).