Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.128.79.88] |
|
Сообщ.
#1
,
|
|
|
Написал маленькую программку, чтобы проверить своё понимание указателей. Компилировал gcc. Не мог понять результат разыменования
указателя "p". Получается *p = 0, а я уверен, что должно быть *p = 10, поскольку указатель "указывает" на массив, который инициализирован. Долго бился с этим вопросом, ничего не нашел. Пришла идея - попробовать компилятор clang. Я никогда его до этого не использовал. И вот результат. В прилагаемом файле всё можно увидеть. На мой взгляд на лицо неадекватное поведение компилятора gcc. А поскольку в это не могу поверить, вопрос - где я ошибаюсь? Прикреплённый файлpointers.txt (2,9 Кбайт, скачиваний: 97) |
Сообщ.
#2
,
|
|
|
У тебя выход за границы массива идет, поэтому и выводится мусор или 0.
Вот тут: Цитата printf("\ a[0] = %d\n\ a[1] = %d\n\ a[2] = %d\n\ p = %p\n\ a[0] = %d\n\ &a[0] = %p\n\ *p = %d\n\ &(*p) = %p\n\ a[0] = %d\n\ *(p+0) = %d\n\ *(p++) = %d\n\ *(++p) = %d\n\ *p++ = %d\n\ *p = %d\n", a[0], a[1], a[2], p=a, a[0], &a[0], *p, &(*p), a[0],\ *(p+0), *(p++), *(++p), *p++,*p); У тебя p инкрементится 3 раза. Последний p = правильный, потому что аргументы функции вычисляются в данном случае с права на лево, соответственно он еще указывает на первый элемент массива. Затем ты его инкрементишь 3 раза, и выводишь еще раз, а он уже указывает на невесть что. Попробуй переписать вот так: printf("\ a[0] = %d\n\ a[1] = %d\n\ a[2] = %d\n\ p = %p\n\ a[0] = %d\n\ &a[0] = %p\n\ *p = %d\n\ &(*p) = %p\n\ a[0] = %d\n\ *(p+0) = %d\n\ *(p++) = %d\n\ *(++p) = %d\n\ *p++ = %d\n\ *p = %d\n", a[0], a[1], a[2], p, a[0], &a[0], *p, &(*p), a[0],\ *(p+0), *(p+1), *(1+p), *(p+1),*p); И все будет работать. Добавлено Ну или сделай массив на больше элементов. |
Сообщ.
#3
,
|
|
|
Вы правы, однако меня шокирует другое. При всех равных условиях разные результаты:
1. clang: a[0] = 10; // Значения первого элемента массива 2. clang: &a[0] = 0x7fffe583d708; // Адрес первого элемента массива 3. clang: &(*p) = 0x7fffe583d708; // Тот же адрес через указатель 4. clang: *p = 10; /*Верно*/ 1. gcc: a[0] = 10; // Значения первого элемента массива 2. gcc: &a[0] = 0x7ffd1ef87d40; // Адрес первого элемента массива 3. gcc: &(*p) = 0x7ffd1ef87d40; // Тот же адрес через указатель 4. gcc: *p = 0; /*Не верно*/ // Шокирует последняя строка - 4. Не могу понять в чем дело? Ведь ошибиться негде, а результат налицо! |
Сообщ.
#4
,
|
|
|
Цитата UriyG @ Шокирует последняя строка - 4. Не могу понять в чем дело? Ведь ошибиться негде, а результат налицо! Ничего шокирующего в этом нет. Есть стандарт, в нем прописано как должны вести себя те или иные конструкции языка, то что не описывается отдается на откуп компилятору, как реализуют так и будет, плюс есть память и есть режимы выполнения(отладочный/релиз), соответственно на шланге возможно аргументы по другому вычисляются, а в элементе за массивом, мусорном оказалось число 10. Вот и все. |
Сообщ.
#5
,
|
|
|
Провел еще серию экспериментов, результат такой. Компиляторы clang и gcc выдают одинаковые результаты только при одном варианте - один printf - только одно число. При других вариантах результаты могут быть разные. Причем, скорее всего clang не ошибается, а gcc - путается!
Добавлено А для меня это - шок! Если в такой простой операции, с "очевидным", как казалось результатом, я имею ввиду операцию разыменования, можно получить совершенно не ожидаемый результат... |
Сообщ.
#6
,
|
|
|
Цитата UriyG @ А не знал, что аргументы функций могут вычисляться в произвольном порядке? А для меня это - шок! |
Сообщ.
#7
,
|
|
|
Цитата UriyG @ Провел еще серию экспериментов,... ... А для меня это - шок! Если в такой простой операции, с "очевидным", как казалось результатом, я имею ввиду операцию разыменования, можно получить совершенно не ожидаемый результат... Просто измени свой исходник так, чтобы вот эти предупреждения не выдавались. Цитата ... g% gcc -Wall -Wextra -Wformat pointers.c -o pointers -std=c11 pointers.c: In function ‘main’: pointers.c:40:39: warning: operation on ‘p’ may be undefined [-Wsequence-point] *(p+0), *(p++), *(++p), *p++,*p); ^ pointers.c:40:39: warning: operation on ‘p’ may be undefined [-Wsequence-point] pointers.c:40:39: warning: operation on ‘p’ may be undefined [-Wsequence-point] pointers.c:40:39: warning: operation on ‘p’ may be undefined [-Wsequence-point] pointers.c:40:39: warning: operation on ‘p’ may be undefined [-Wsequence-point] pointers.c:40:39: warning: operation on ‘p’ may be undefined [-Wsequence-point] pointers.c:40:39: warning: operation on ‘p’ may be undefined [-Wsequence-point] ... Тебя же предупреждали... |
Сообщ.
#8
,
|
|
|
Да, я не знал, что аргументы функций могут вычисляться в произвольном порядке.
Вернее знал, но о printf не подумал. Огромное спасибо! Это я запомню на всегда! Добавлено Цитата UriyG @ Кстати, clang не ошибся, если так можно сказать, ни разу! |