1. Pascal / Говнокод #13444

    +88

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    13. 13
    14. 14
    15. 15
    16. 16
    17. 17
    18. 18
    19. 19
    20. 20
    21. 21
    22. 22
    23. 23
    24. 24
    25. 25
    26. 26
    27. 27
    28. 28
    program Project6;
    
    {$APPTYPE CONSOLE}
    
    uses SysUtils;
    
    type TIntArr = array of integer;
    
    function GetSingleArr (i: integer): TIntArr;
    begin
      SetLength(Result, 1);
      Result[0] := i;
    end;
    
    var
      W: TIntArr;
      i : integer;
    begin
      readln(i);
      if i=0 then begin
        W := GetSingleArr(5);
        WriteLn(W[0]);
      end;
      ReadLn;
    end.
    
    Delphi-7
    [Warning] Project6.dpr(25): Variable 'W' might not have been initialized

    Да какого хуя? Динмассив вообще по определению - чисто автоматический тип, как он может не инициализироваться?
    И почему для других типов такая хрень не вылазит?

    Запостил: TarasB, 18 Июля 2013

    Комментарии (60) RSS

    • Писец, вот что крест живородящий творит, а...
      Ответить
    • begin
        W := GetSingleArr(5);
        if i=0 then begin
          readln(i);
          WriteLn(W[0]);
        end;
        ReadLn;
      end.


      z.pas(21) Hint: Value assigned to 'i' never used
      z.pas(20) Warning: Variable 'i' might not have been initialized

      А у меня наоборот!
      Ответить
      • Ты используешь i, не инициализируя.
        У меня ничего подобного не происходит - W я использую только в ветке, в которой я его явно инициализирую (в других он инициализируется неявно). Если я вместо TIntArr применю иной тип (например, String), то этого предупреждения не будет, вот что самое дурацкое.
        Ответить
        • Да, действительно, ругается только на динамический массив и только Дельфи. FPC ворнинга не выдаёт.

          P.S. На type TIntArr = array [0..9000] of integer; Дельфи не ругается. Ругается только на динамический.
          Ответить
        • например String? :)
          Стринги всегда инициализируются компилятором, это не пример.
          Такой пример наводит на какие-нибудь мысли, не?
          var
            x : ^integer;
            i : integer;
          begin
            readln(i);
          
            if i=0 then
            begin
              x^ := i;
              Writeln(x^);
            end;
          
            ReadLn;
          end.

          или даже
          var
            x : ^string;
          Ответить
          • А почему при вынесении W := GetSingleArr(5); до ветвления ворнинг исчезает?
            Ответить
            • потому что W в таком случае инициализируется для всего scope...
              Ответить
          • > Стринги всегда инициализируются компилятором, это не пример.

            Динмассивы тоже.

            > Такой пример наводит на какие-нибудь мысли, не?

            Не имеет никакого отношения, тут запись в хзкакой адрес.
            Мой код 100% корректен.
            Ответить
        • вот такой вариант уже warning'a не даст
          var
            W: array of integer;
            i : integer;
          begin
            readln(i);
            if i=0 then begin
              SetLength(w, 1);
              w[0] := i;
              WriteLn(W[0]);
            end;
            ReadLn;
          end.

          Теперь сравни с предыдущим примером и пойми почему :)
          Ответить
          • Я знаю, что такой пример не даёт предупреждения.
            Сравнил.
            Ну, и почему же мой пример даёт предупреждение?
            Ответить
            • А я понял, почему. Предупреждение выскакивает, если компилятор не находит в коде явной установки длины динамического массива. Он не знает, какое значение вернёт функция GetSingleArr: с определённой длиной или с неопределённой.
              Ответить
          • Код Тараса:
            GetSingleArr	proc near
            		push	ebx
            		push	esi
            		mov	ebx, edx ; последний аргумент — это адрес Result
            		mov	esi, eax ; первый аргумент — это i
            		push	1
            		mov	eax, ebx
            		mov	ecx, 1
            		mov	edx, off_4087AC    ; ссылка на RTTI для array of integer
            		call	@DynArraySetLength ; SetLength(Result, 1);
            		add	esp, 4
            		mov	eax, [ebx]         ; в ebx сейчас адрес Result
            		mov	[eax], esi	   ; Result[0] := i;
            		pop	esi
            		pop	ebx
            		retn
            GetSingleArr	endp
            
            
            initialization_5 proc near
            
            var_14		= dword	ptr -14h
            
            		push	ebp
            		mov	ebp, esp
            		add	esp, 0FFFFFFECh
            ... 
            		lea	edx, [ebp+var_14]  ; место под Result выделено в стеке
            		mov	eax, 5
            		call	GetSingleArr       ; W := GetSingleArr(5);
            		mov	edx, [ebp+var_14]
            		mov	eax, offset dword_40A798 ; адрес W
            		mov	ecx, off_4087AC    ; адрес RTTI для array of integer
            		call	@DynArrayAsg
            		mov	eax, ds:dword_40A798 ; W
            		mov	edx, [eax]	   ; W[0]

            Этот код:
            push	1
            		mov	eax, offset dword_40665C ; адрес W
            		mov	ecx, 1
            		mov	edx, off_40418C          ; RTTI для array of integer
            		call	@DynArraySetLength       ; SetLength(w, 1);
            		add	esp, 4
            		mov	eax, ds:dword_40665C     ; W
            		mov	esi, ebx                 ; i
            		mov	[eax], esi               ; W[0] := i;

            В чём разница, кроме вызова DynArrayAsg для копирования массива из безымянной переменной в стеке в W?
            Ответить
        • показать все, что скрытоТы используешь Паскаль - нет тебе оправдания, питушок :)
          Ответить
    • Тарас, завязывай ты с этим мертвым языком. Переходи или к Каролю в гнутые сишники или ко ко ко мне в Хаскелисты. Будем нагбибаторами всех нагибать. В двоем больше сможем.
      PS: Или будь уникален и линяй на Аду. Тоже есть чем нагибать.
      Ответить
      • А чем плох Паскакаль? В Паскакале кококонкатенация строк самая-пресамая быстрая в мире!
        Ответить
        • >кококонкатенация строк самая-пресамая быстрая в мире!
          Какого? Да и причем тут язык?
          Ответить
          • Но ведь в нём нет сишных строк с завершающим нулём, на поиск которого тратятся драгоценные такты!
            Ответить
            • в FPC есть, я гарантирую это.
              А еще, что вам мешает на Си реализовать контейнер паскалестрок?
              А да еще, в этом ваши делфи освобождением памяти от строк(и от дин.массивов) занимается GC, что куда дороже, чем нультерминированная строка.
              http://stackoverflow.com/questions/4440841/garbage-collection-in-delphi

              По поводу данного кода: W может не инициализироваться, если цикл будет выполнен 0 раз, к этому выводу приходит компилятор, анализируя Control-Flow-Graph. Поэтому тут все в порядке.
              Ответить
              • 1. Вы же догадываетесь, что я утрирую. PChar с завершающим нулём появился ещё в Турбо Паскале. И самодельный контейнер паскалестрок в сишечке Царь нам уже показывал.

                2. За ссылку спасибо, посмотрю.

                3. Если цикл будет выполнен 0 раз, то переменная использована будет тоже 0 раз.
                Ответить
                • >1. Вы же догадываетесь, что я утрирую. PChar с завершающим нулём появился ещё в Турбо Паскале. И самодельный контейнер паскалестрок в сишечке Царь нам уже показывал.
                  Это не паскаль строки - это сишные строки, только с добавночной длинной. Т.е. сама длинна строки к строке не имеет отношения, она имеет отношение только к указателю.

                  В питух паскаль строке - сделанно как в маллоке. char * str; *(uint16_t *)str = len;

                  И да, самая быстрая конкатенация строк в сишке. Была и всегда будет.
                  Ответить
                • Какая разница, сколько раз будет выполнен цикл? И что переменная не будет использована?
                  Компилятору все равно, он всего лишь анализирует граф потока управления.
                  array of T в паскале - не более чем указатель.
                  Ответить
                  • > array of T в паскале - не более чем указатель.

                    Это указатель с автоматикой. И только на нём компилятор клинит в паранойю. На string - не клинит.
                    Ответить
                    • Все правильно. String - аллоцируется перед использованием, а дин.массив - нет. Как по мне - так это вполне логично.
                      И сравнивать string и array of T некорректно, имхо.
                      А вот string^ и array of T уже можно, ибо и то и то - указатели.
                      Ответить
                      • > Все правильно. String - аллоцируется перед использованием, а дин.массив - нет.

                        Нихуя подобного, они оба инициализируюся нилом, учи матчасть.
                        Ответить
                • показать все, что скрытоОтсосу член парню из Владикавказа. Прут наглые хуястые самцы.

                  [email protected] (Спросить Тараса)
                  Ответить
              • > в этом ваши делфи освобождением памяти от строк(и от дин.массивов) занимается GC
                Да откуда там GC!? Емнип, на строках только счетчик ссылок, только хардкор.
                Ответить
                • Мне честно лень разбираться, что там в делфи, но:
                  ARC часто рассматривают как частный случай GC;
                  GC вполне себе реализуется в языках с компиляцией в натив.
                  Однако, если бы было ARC, то при каждой циклической ссылке в объектах - происходила бы утечка памяти.
                  Ответить
                  • > ARC часто рассматривают как частный случай GC;

                    Не путай ГЦ и автодеструкторы, у них есть очень, очень важные отличия.
                    Ответить
                    • Отследить время жизни поинтера не всегда возможно. Вот разработчики Rust пытаются, ввели 4 разных модели памяти, проверку времени жизни и тд, но все равно не всегда это удается :)
                      Ответить
                      • В случае строк и динмассивов и - проблем быть не может, а если проблемы и будут из-за того, что где-то повис указатель со ссылкой на эту строку - то это проблемы этого указателя и без этой строки это по-прежнему была бы проблема.
                        Ответить
                      • А важнейшее отличие автодеструкторов - это гарантированный вызов в конце блока. И это крайне важно для системных ресурсов, которые действительно необходимо освободить здесь и сейчас. Например, критические секции. ГЦ для них вообще неприменим.
                        Ответить
                        • Это происходит только если такой тип не возвращается из функции.
                          Ответить
                          • При возврате из функции вызывается либо оператор перемещения, либо оператор = с деструкцией старого экземпляра, их тоже можно описать так, что всё будет корректно.
                            Ответить
                  • > если бы было ARC, то при каждой циклической ссылке в объектах
                    Откуда взяться циклическим ссылкам в строках? А для объектов там ARC и не работает.

                    > происходила бы утечка памяти
                    Проблема, на самом деле, довольно надуманная. А если есть weak_ptr и немного мозгов - ее вообще почти не существует.
                    Ответить
                    • И в динмассивах, содержащих только поды, строки и динмассивы ранее описанных типов (иначе [Error] Type 'T' is not yet completely defined), тоже неоткуда.
                      А вот если в динмассив запечь RC-интерфейс с полем с таким динмасивом, то тут таки да, будут проблемы.
                      Ответить
                      • Да особых проблем не будет, если не мутить кольцевые ссылки.
                        Ответить
                        • Но придётся следить за тем, чтобы они не мутились.
                          Ответить
                    • > Откуда взяться циклическим ссылкам в строках? А для объектов там ARC и не работает.
                      Если строки реализованы как "веревки" (ropes), то вполне может получиться, если тому, кто реализовывал захочется хранить указатели в обе стороны (от родителей к детям и обратно).
                      Ответить
              • > А да еще, в этом ваши делфи освобождением памяти от строк(и от дин.массивов) занимается GC, что куда дороже, чем нультерминированная строка.

                Какой нахуй GC?

                > W может не инициализироваться, если цикл будет выполнен 0 раз

                Где цикл? W нужна и используется только внутри одной ветки.
                Что сука характерно, если вместо TIntArr взять любой другой тип, хоть string,похожий по принципу работы, то этого неуместного предупреждения не будет.
                Ну и как вообще динмассив может не инициализироваться, если это автоматический тип?
                Ответить
                • Это обычный указатель, я уже писал. И ведет он себя как указатель, то есть его нужно самому аллоцировать(вызов setlength), а string - аллоцируется автоматически.
                  Ответить
                  • > И ведет он себя как указатель, то есть его нужно самому аллоцировать(вызов setlength)

                    Учи матчасть, он инициализируется нилом. Иначе бы при первой смене длины он попытался бы освободить старый мусор, пиздец же был бы, да?

                    > а string - аллоцируется автоматически.

                    Учи матчасть, нихуя он не аллоцируется, он инициализируется нилом.
                    Ответить
                    • Да ты что? К твоему сведению, паскале строка выглядит как:
                      struct{
                      int len;
                      char* str;
                      };
                      И соответственно при входе в процедуру выделяется память(чаще всего на стеке, если строка не возвращается) для длины и указателя.
                      Шел бы сам матчать учил.

                      PCHar конечно же устанавливается в nil, но мы же о обычных паскале строках.
                      Ответить
                      • > К твоему сведению, паскале строка выглядит как:

                        Откуда ты знаешь? Это в крестах так, а в Дельфи - не так.
                        Ты ж нихуя не знаешь, только умными словами на английском языке кидаться горазд, лолка.

                        К твоему сведению, в Паскале строка выглядит так:
                        type
                          PStrRec = ^StrRec;
                          StrRec = packed record
                            refCnt: Longint;
                            length: Longint;
                          end;

                        Дальше берётся что-то типа
                        record
                          Head : StrRec;
                          Chars : array [1..1] of char;
                        end;

                        Потом при SetLength вызывается аллокатор для NewLength+SizeOf(StrRec)
                        После чего возвращается указатель не тот, что вернул аллокатор, а P+SizeOf(StrRec), то есть строка - это указатель на первый символ, а перед ним идут ещё 8 байт структуры StrRec.

                        > но мы же о обычных паскале строках.

                        Обычные - это которые до 255 символов? Я не про них.
                        Ответить
                      • А давайте проверим, не читая документацию?
                        http://ideone.com/l58zHK

                        string[N] (точнее ShortString) — это struct { char len; char str[N]; }; Да, никаких указателей и никаких интов, только чар, только хардкор.

                        String без указания длины — это указатель на str[1].

                        array of char — это указатель на array [0..длина - 1] of char. Аналогично, AnsiString, WideString, UTF8String — такие же указатели на массив.
                        Ответить
                        • Приношу извинения. Просто String в новых Дельфях и в FPC компилируется в AnsiString: http://ideone.com/R2dCVa

                          А ShortString — это struct { char len; char str[N]; }, как и string[N].
                          Ответить
                        • И ещё один тест: http://ideone.com/RhZeoK

                          Если разыменовать AnsiString, WideString, UTF8String, то по смещению минус четыре перед массивом хранится его размер в байтах. А если разыменовать array of char, то перед массивом по смещению минус восемь хранятся два числа: диапазон его индексов (а по смещению минус двенадцать — вероятно, тип элементов).
                          Ответить
    • В таком коде тоже ругается:
      var w: TIntarray;
      begin
      end;
      если заменить на string, то варнинг пропадает. разница - в вызове _DynArrayClear или LStrClr.
      Причем, аргумент, который указатель на строку/массив передавется одинаково.
      Глюк компилятора, походу.
      Ответить
      • Именно.
        Но в таком коде хотя бы есть неиспользуемые переменные.
        Я постарался подобрать код, который не должен вообще выдавать претензий.
        Ответить
        • аа, я так и подумал.
          кстати, если в начале добавить w := NIL, варнинг пропадает.
          а разница вот в чем (модуль system):
          procedure _LStrClr(var S);
          procedure _DynArrayClear(var a: Pointer; typeInfo: Pointer);
          Ответить
          • > а разница вот в чем (модуль system):

            Ну да, неявно вызываются разные функции, всё равно не понимаю. Один из них не помечена как "считать что переменная использована если вызывается"?
            Ответить
            • а вот хз - может, указание типа так действует?
              в любом случае - фигня какакя-то.
              Ответить
    • ты дурак
      Ответить

    Добавить комментарий