На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Модераторы: Qraizer, Hsilgos
  
> Сравнение результатов компиляции gcc и clang , gcc и clang дают разные результаты при компиляции одной и той же программы на Си
    Написал маленькую программку, чтобы проверить своё понимание указателей. Компилировал gcc. Не мог понять результат разыменования
    указателя "p". Получается *p = 0, а я уверен, что должно быть *p = 10, поскольку указатель "указывает" на массив, который инициализирован.
    Долго бился с этим вопросом, ничего не нашел. Пришла идея - попробовать компилятор clang. Я никогда его до этого не использовал. И вот результат. В прилагаемом файле всё можно увидеть. На мой взгляд на лицо неадекватное поведение компилятора gcc. А поскольку в это не могу поверить, вопрос - где я ошибаюсь?
    Прикреплённый файлПрикреплённый файлpointers.txt (2,9 Кбайт, скачиваний: 97)
      У тебя выход за границы массива идет, поэтому и выводится мусор или 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 раза, и выводишь еще раз, а он уже указывает на невесть что.
      Попробуй переписать вот так:
      ExpandedWrap disabled
            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);

      И все будет работать.

      Добавлено
      Ну или сделай массив на больше элементов.
        Вы правы, однако меня шокирует другое. При всех равных условиях разные результаты:



        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. Не могу понять в чем дело? Ведь ошибиться негде, а результат налицо!
        Сообщение отредактировано: UriyG -
          Цитата UriyG @
          Шокирует последняя строка - 4. Не могу понять в чем дело? Ведь ошибиться негде, а результат налицо!

          Ничего шокирующего в этом нет. Есть стандарт, в нем прописано как должны вести себя те или иные конструкции языка, то что не описывается отдается на откуп компилятору, как реализуют так и будет, плюс есть память и есть режимы выполнения(отладочный/релиз), соответственно на шланге возможно аргументы по другому вычисляются, а в элементе за массивом, мусорном оказалось число 10. Вот и все.
            Провел еще серию экспериментов, результат такой. Компиляторы clang и gcc выдают одинаковые результаты только при одном варианте - один printf - только одно число. При других вариантах результаты могут быть разные. Причем, скорее всего clang не ошибается, а gcc - путается!

            Добавлено
            А для меня это - шок! Если в такой простой операции, с "очевидным", как казалось результатом, я имею ввиду операцию разыменования, можно получить совершенно не ожидаемый результат...
              Цитата UriyG @
              А для меня это - шок!
              А не знал, что аргументы функций могут вычисляться в произвольном порядке?
                Цитата 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]
                ...

                Тебя же предупреждали...
                Сообщение отредактировано: ЫукпШ -
                  Да, я не знал, что аргументы функций могут вычисляться в произвольном порядке.
                  Вернее знал, но о printf не подумал.
                  Огромное спасибо! Это я запомню на всегда!

                  Добавлено
                  Цитата UriyG @

                  Кстати, clang не ошибся, если так можно сказать, ни разу!
                  Сообщение отредактировано: UriyG -
                  0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                  0 пользователей:


                  Рейтинг@Mail.ru
                  [ Script execution time: 0,0317 ]   [ 17 queries used ]   [ Generated: 19.04.24, 10:08 GMT ]