1. Си / Говнокод #2637

    +99.4

    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
    #include <iostream>
    
    int *sfirst_function(void);
    int *isecond_function(void);
    
    int * sfirst_function(void)
    {
    	int ilocal_to_first=11;
    	return &ilocal_to_first; // Возвращаем указатель на переменную, размещенную в стеке
    } 
    
    int *isecond_function(void)
    {
    	int ilocal_to_second=44;
    	return &ilocal_to_second; // ну и тут
    }
    void main()
    {
    	int *pi=sfirst_function();
    	printf("First Function = %d\n",*pi);
    	int *si= isecond_function();
    	printf("Second Function = %d\n",*si);
    }

    Найдено на античате, в топике "помощь с лабораторными"
    В этом конкретном примере, конечно, допустим возврат адреса локальной переменной, а вот в более крупном проекте автор столкнулся бы с нефиговой проблемой =)

    Запостил: RankoR, 18 Февраля 2010

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

    • static спасёт отца русской демократии.
      Ответить
    • А нафига это нужно то?
      Ответить
    • Человек-gcc приходит на помощь:

      : In function ‘int* sfirst_function()’:
      :8: предупреждение: возвращен адрес локальной переменной ‘ilocal_to_first’
      : In function ‘int* isecond_function()’:
      :14: предупреждение: возвращен адрес локальной переменной ‘ilocal_to_second’
      : At global scope:
      :17: ошибка: ‘::main’ должна возвращать ‘int’


      Закроем глаза на использование iostream в си.
      Ответить
    • Нафига так делать - для меня осталось загадкой. Как и иострим, кстати говоря =)
      Ответить
      • Точно.
        Где здесь Си?
        Нет. :)
        Ответить
        • Это С++. Только не спрашивайте где он. :)
          Ответить
          • Изначально в теме ЭТО было объявлено кодом на С. Хотя это и кодом-то сложно назвать.
            Ответить
            • #include<iostream.h>
              /* ... */
              cout << "Znachennya virne?" << *pi;}

              Вот когда в це будет iostream, тогда и приходите. А от того, что автор той темы не разбирается в том, на чём код - це, це-минус-минус, питон, труболисп для макинтош — не изменится ровным счётом ничего.
              Ну а потом — таки да, переписали под универсальный вариант.
              Ответить
    • Естественно, на тех же сях или сях с крестами есть немало способов выстрелить себе в голову зарядом дроби или ректально себя изнасиловать. Тем не менее, для какого-то вида изврата вполне может и подойти. Если в языке есть какая-то нетипичная возможность, не значит, что она совсем бесполезна, возможно, ей просто нужно уметь пользоваться.
      Возвращаясь к нашим баранам. Это, вроде как, вполне клинический случай, но особым говнокодом и не пахнет. Тем не менее, гораздо красивее и тоньше, нежели все эти if ( (a==b)? true : false), которые форсятся школотой. Плюсую, за идею.
      Ответить
    • Если хочется сокрытия переменной глобальной переменной. То объявляется в cpp файле и все, да и как static.
      Ответить
    • Методом гугления выявлен следующий документ: "Visual C++ 6 Руководство разработчика"
      Параграф:

      Функции, возвращающие адреса
      Когда функция возвращает указатель или ссылку, результатом выполнения функции
      становится адрес в памяти компьютера. Пользователь может прочитать значение,
      сохраненное по этому адресу, и даже, если указатель не был объявлен со спецификатором
      const, записать туда свои данные. Это может привести к возникновению трудно
      обнаруживаемых ошибок в программах. Посмотрим, сможете ли вы разобраться в том, что
      происходит в следующей программе.
      //
      // refvar.cpp
      // Эта программа на языке C++ демонстрирует,
      // чего НЕ нужно делать с адресами переменных.
      //
      #include <iostream.h>
      int *ifirst_function(void) ;
      int *isecond_function(void);
      void main(){
      int *pi = ifirst_function ();
      isecond_function();
      cout<< "Это значение правильное? " << *pi;}
      int *ifirst_function(void){
      int ilocal_to_first = 11;
      return &ilocal_to_first;}
      int *isecond_function(void){
      int ilocal_to_second = 44;
      return &ilocal_to_second;}

      Этим объясняется и iostream, и бредовость идеи. Логически рассуждая можно сделать вывод, что некий преподаватель решил выдать школотестудиозусам "хитровыебанную задачу", спросив, а что тут не так. Посему, человек и ткнулся на отнечад. Посему мы и наблюдаем сугубо учебный пример.
      Вывод - не говнокод.
      Ответить
    • А вы поступите подобным образом в более крупном проекте - и посмотрим, какой это не говнокод ;)
      Если человек так поступил в маленьком проекте - следовательно, не задумавшись сделает так же и в большом
      Ответить
    • Йопт, пример учебный. Более того, говорит, что так делать не надо. А если кто-то придумывает извращённый учебный пример, то это никак не коррелирует с качеством кода.
      С какого количества строк проект считается крупным?
      Ответить
    • показать все, что скрытоГДЕ ЗДЕСЬ СИ?!
      Ответить
    • Обращу ваше внимание на то, что пример был дан на полном серьезе как рабочий код, а не "вот так вот делать не надо". Комментарии там - мои.

      Крупный - понятие относительное. БОЛЕЕ крупный - хотя бы строк 200 (этого будет вполне достаточно, чтобы показать, что код неработочпособен). А вот если кода будет over 50k, то уже пензес, в жизни не найдешь, где ошибка.
      Ответить
    • Можно легко и ненавязчиво написать проект в тысячу строк с такой методикой и всё будет прекрасно работать. Более того, можно использовать сею технику для какого-нибудь изврата, например, для понижения восприятия человека, который это дело отлаживать будет. В некоторых случаях жёсткая привязка к стековому адресу только в пользу.
      Обращу Ваше внимание, что я нашёл топик на онтечаде, и там не было ни слова про то, что код рабочий. Один человек спросил, почему его вариант кода не компилируется (лишняя точка с запятой), его вариант был точной копипастой из "Visual C++ 6 Руководство разработчика", только текст был транслитом. Другой исправил и запостил, в том же самом виде. Третий оставил декларацию iostream, но переписал на printf.
      Прозреваю, что задание на лабу было разобраться, почему так кодить нельзя.
      Все эти Ваши домыслы, что код рабочий, совершенно неуместны. Это демонстрация, криво переписанная и похабно разъяснённая. Ололо?
      Ответить
    • Этот код, кстати, работает в VC только потому, что функции инлайнятся и реально под переменные выделяется память в стеке в мэйне. Вообще, без оптимизатора, должно произойти следующее:
      Ответить
      • Тут мало того что наврал, так еще и не дописав отправил, не читайте =)
        Ответить
    • Этот код, кстати, работает в VC потому, что функции инлайнятся и реально под переменные выделяется память в стеке в мэйне. Хотя и вообще, без оптимизатора, должно произойти следующее:
      перед вызовом первой функции:
      .... <----- несколько двордов
      1 dword
      2 dword
      3 dword
      4 dword <----esp

      потом, перед возвратом из функции:

      .... <----- несколько двордов == saved registers
      1 dword <----local var
      2 dword <----ebp
      3 dword <----ret address
      4 dword

      Т.е. мы получаем адрес нашей локальной переменной 1., и во время вызова принтфа, перед тем, как испортить значение в стеке адресом возврата, мы получаем его и передаем в принтф. Кстати, если бы параметров принтфу было побольше, то с некоторой вероятность значение по адресу pi вычислялось после того, как в стек засунуты 3 параметра и было равно значению третьего параметра, если ниче не напутал. Вод =)
      Ответить
    • а почему бы просто не сказать, что обе функции выделяют локальную переменную в одном месте стека?
      Ответить

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