На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Модераторы: Qraizer, Hsilgos
  
> возврат из функции константного указателя , Си (С89 или С90 не знаю, но точно кто-то из них!)
    Всем хай! Сходу к делу!

    Есть такая придуманная функция:
    ExpandedWrap disabled
      char* const F( void )
      {
          char* buf = ( char* )malloc( 100 );
          strcpy( buf, "abcdefghijklmnop" );
          return buf + 3;
      }


    возвращает она КОНСТАНТНЫЙ указатель. Можно было бы вообще так записать, мол const char* const F ..., но пока БЕЗ первого конст.

    В главной функции есть такой вызов:
    ExpandedWrap disabled
      void main( void )
      {
          char* p = NULL;
          char* s = F();
       
          s = p;
          // printf( s );
          
          printf( "\n\n" );
          system( "pause" );
      }

    да, есть утечка памяти, но на это пока наплевать вообще)

    меня интересует, почему компилятор пропускает это:
    ExpandedWrap disabled
          s = p;

    ведь вернулся константный указатель. Или дело в том, что объявление s не является константным указателем и нужно так:
    ExpandedWrap disabled
      char* const s = F();


    да, тогда ругается на строку s = p;
    Но почему тогда компилятор в принципе позволяет смешивать конст. и не конст указатели, т е почему пропускает эту строку:
    ExpandedWrap disabled
      char* s = F();


    должен ведь был сообщить, что делается попытка присвоить константный указатель В НЕКОНСТАНТНЫЙ

    я правильно все описал??)
    Сообщение отредактировано: FasterHarder -
      Цитата FasterHarder @
      меня интересует, почему компилятор пропускает это:
      ...
      Ну ты же можешь написать
      ExpandedWrap disabled
        const int x = 123;
        int y = x;
      В чём проблема, если вместо int будет указатель? Вот если б у себя был const char*, тогда это были бы указатели на разные типы, а так всего лишь переменные, чьи значения просто копируются.
      Цитата FasterHarder @
      ... тогда ругается на строку s = p;
      Ну и правильно. Ты пытаешься изменить значение константной переменной.
        Цитата Qraizer @
        В чём проблема, если вместо int будет указатель?

        спс, кажется понял)

        Цитата Qraizer @
        Вот если б у себя был const char*, тогда это были бы указатели на разные типы

        ExpandedWrap disabled
          char* const F( void )
          {
              char* buf = ( char* )malloc( 100 );
              strcpy( buf, "abcdefghijklmnop" );
              return buf + 3;
          }
           
           
          void main( void )
          {
              char* p = NULL;
              const char* s = F();



        из функции F возвращается константный указатель, а присваивается это значение в указатель на константные данные. Все компилируется, все запускается. Но ты ведь, наверное, не на это намекал?

        еще такой момент: такое легально в Си?
        ExpandedWrap disabled
          const char const * const s = ...


        Добавлено
        А в целом я случайно наткнулся на возврат константных указателей из функций, т к практически вообще этого нигде нету и в кодах просто возвращают тип* да и все
        Но мне потребовалось вернуть значение strchr из функции, и компиляция НЕ проходила, какое-то время не мог понять фишку, а потом увидел прототип этой strchr - возвращает константный указатель, правда там перегрузка этой функции и в 1ой версии просто char* без всяких конст возвращается) + тип 1ого параметра конст и простой

        это я так написал, к слову...
          Цитата FasterHarder @
          Но ты ведь, наверное, не на это намекал?
          Не на это. Имелось в виду, если функция будет возвращать const char*, а не chat* const.
          Цитата FasterHarder @
          еще такой момент: такое легально в Си?
          Конечно. Первые два const фактически дублируют друг друга, но это не ошибка, const const int, например, тоже не запрещено. Важно, стоит ли const до * или после. До относится к указываемым данным, после – к самому указателю. Могут стоять и в обоих местах, почему нет.
            Цитата Qraizer @
            Не на это. Имелось в виду, если функция будет возвращать const char*, а не chat* const.

            понятно, проверил, действительно так и есть, т е если функция возвращает константу на данные, то ОНА (функция) хочет быть уверена, что за ЕЕ пределами эти данные останутся нетронутыми)

            Цитата Qraizer @
            Конечно. Первые два const фактически дублируют друг друга, но это не ошибка, const const int, например, тоже не запрещено. Важно, стоит ли const до * или после. До относится к указываемым данным, после – к самому указателю. Могут стоять и в обоих местах, почему нет.

            отлично, понятно

            кстати, такой вариант значит тоже проходит :lol:
            ExpandedWrap disabled
              const const char* const const s = F();

            и все компилируется и запускается без проблем...

            и даже такой :lol: :lol:
            ExpandedWrap disabled
              const const char* const const const const s = F();

            интересно, не думал, что такое будет пропускать компилятор - ну ладно)

            Но в целом правило такое, как я понимаю для указателей: достаточно ДВУХ КОНСТ для полной защиты: 1 - ДО *, 2 - ПОСЛЕ *, все остальные КОНСТ избыточные по своей сути...

            Эти два объявления указателей абсолютно одинаковые с точки зрения константности:
            ExpandedWrap disabled
                  char const * const s = ...
                  const char* const s = ...


            но 2ой вариант выглядит намного симпатишнее имхо)

            ---------------------------------
            Почти все авторитеты в области программинга люто рекомендуют ставить const где это только возможно, прямо по максимуму. Если есть - надо ставить. Это немного удлиняет все декларации и пр., но дает доп.мощную защиту, как я понимаю.
            Qraizer, у тебя такое же мнение насчет использования const в коде на языке Си? Т е ставить по максимуму и точка или все-таки...)
              FasterHarder, видишь ли, ты можешь действовать по инструкции и в ус не дуть. И всё будет хорошо почти всегда, и ты можешь всем говорить, что ты крутой, и хорошо всё делаешь и демонстрировать, насколько. А все будут соглашаться. Только есть нюанс: знать, как правильно, и понимать, почему именно так правильно – это две огромнейшие разницы.
              Авторитеты советуют дело, но понимаешь ли ты, откуда взялись эти советы? Я нередко вижу что-то типа такого:
              ExpandedWrap disabled
                void f(const int x, const char* msg);
              и когда спрашиваю, зачем там const, внятного ответа услышать удаётся нечасто. Обычно "ну так все советуют". Ты можешь ответить на этот вопрос касательно этой функции?
                Цитата Qraizer @
                и когда спрашиваю, зачем там const, внятного ответа услышать удаётся нечасто. Обычно "ну так все советуют". Ты можешь ответить на этот вопрос касательно этой функции?

                1. А что делает это функция F? )
                2. Какова роль этих формальных параметров?

                const x - блокируют от изменений, чтобы в расчетах было верное значение)
                const char* msg - это ведь какой-то диалог для пользователя и msg указывает на конст.данные. Чтобы диалог был напечатан правильно и случайно не изменен внутри функции

                ну, вот мои примерно ответы, но это ты мне не сказал ответы на вопросы 1) и 2).

                и добавлю, что ставить const советуют авторитеты)) по этой причине не хватает 2ого конст у msg, хотя не факт, что он там нужен...

                Добавлено
                3) Как вызывается эта функция F? (примеры вызовов)
                  Чтоб не размазывать, давай так.
                  Цитата FasterHarder @
                  3) Как вызывается эта функция F? (примеры вызовов)
                  Самый последний, но и самый правильный вопрос. Ответ на нет: а какая тебе разница?
                  Видишь ли, FasterHarder, прототип функции декларирует её контракт. Абсолютно неважно, как она обращается со своими параметрами внутри, главное, что она декларирует наружу. А наружу она декларирует, что обязуется не менять свои параметры. Мне пофигу, как она внутри устроена, мне важно, чтоб она выполнила свой контракт (конкретно в этом примере неважно, каков он; конечно, в реальном коде я буду знать, что функция делает, иначе зачем же я её зову-то) и чтобы она не нарушила свои обязательства. Поэтому я вполне могу её вызывать как:
                  ExpandedWrap disabled
                    f(123, "прими это как данное");
                     
                    /* ... */
                     
                    int  myAge = 50;
                    time_t now = time(NULL);
                     
                    f(myAge, asctime(localtime(&now)));
                     
                    /* и даже так */
                     
                    FILE *p = fopen("CON", "at");
                    FILE *q = fopen("CON", "rt");
                    char  myName[16];
                     
                    fprintf(p, "Who are you? "); fflush(p);
                    fscanf(q, " %15s", myName);
                    fclose(q);
                    fclose(p);
                     
                    f(rand(), myName);
                  Особенно интересен последний пример: я уверен, что myName останется неизменным, потому что const char* это гарантирует. Вот если б там было просто char*, я вынужден был бы предполагать, что f() испортит моё имя, с таким трудом полученное с консоли, и если это не входит в мои планы, придётся передавать её копию myName.

                  Итого. const в параметрах – это контракт функции. Безусловно важно всем сообщать о том, что не собираешься модифицировать аргументы, если и правда не собираешься. Это особенно важно, когда по указателю передаются структуры, сразу видно, что это просто оптимизация, чтоб структура не копировалась, а не попытка через эту структуру передать обратно результаты работы. И наконец финальный вопрос: зачем у первого параметра const? Мне не пофик ли, что она там внутри с ним делает, если он всё равно пришёл туда по значению?
                    Цитата Qraizer @
                    наконец финальный вопрос: зачем у первого параметра const? Мне не пофик ли, что она там внутри с ним делает, если он всё равно пришёл туда по значению?
                    Поскольку FasterHarder, похоже, утратил интерес к теме, попробую я: как и с локальными переменными, уберечь себя от (не)преднамеренного изменения значения этой переменной внутри реализации функции.

                    Добавление от Qraiser: Видя же подобную ересь во внешнем интерфейсе, я буду скорее склонен подвергнуть сомнению качество реализации её автором, ибо автор тупо не понимает, зачем он оформляет те или иные сущности модели в те или иные сущности кода.
                    Сообщение отредактировано: Dushevny -
                      Ок, Dushevny, а мне-то зачем об этом знать? Это личные трудности автора реализации, на кой они напоказ выставляются в публичном интерфейсе?
                      Вопрос не в том, как проще автору реализации, он один, а в том, как проще потребителям опубликованного им интерфейса. А их вообще-то вагон, и они смотрят на сие и недоумевают, как им теперь относиться к качеству реализации этой библиотеки, коли её автор... хм, несколько неграмотен.
                      Если только, конечно, автор реализации, не самоудовлетворяется в рамках собственного проекта. Но тогда я этого маразма и не увижу. М-м-м... по идее.

                      Добавлено
                      P.S. Вообще, видеть подобно сродни
                      ExpandedWrap disabled
                        printf("It's - %d - some int value\n", (const int)x);
                      где x исходно имеет целый тип, только неконстантный. Почему так никто не пишет? Ответ такой же, как на вопрос "почему const в параметрах-значениях" вызывает диссонанс.

                      Добавлено
                      P.P.S. Чтоб исключить кривотолки. Прототип предназначен для документирования интерфейса функции. Компилятору и программисту в равной степени. Во внешнем интерфейсе нет места внутренним аспектам реализаций. Этот тезис суть явное следствие предназначения прототипа функции. Видя же подобную ересь во внешнем интерфейсе, я буду скорее склонен подвергнуть сомнению качество реализации её автором, ибо автор тупо не понимает, как и почему именно так он оформляет те или иные сущности реализуемой им мат.модели в те или иные сущности кода. Следовательно я не могу доверять и качеству других аспектов его кододеятельности.
                        Цитата Dushevny @
                        Поскольку FasterHarder, похоже, утратил интерес к теме

                        ты давай не гони тут! ничего я не утратил, просто Qraizer дает много информации для проверок и размышлений...

                        Цитата Qraizer @
                        И наконец финальный вопрос: зачем у первого параметра const?

                        я сейчас вообще, где только возможно константю копии передаваемых параметров, чтобы ПОДЧЕРКНУТЬ, что это ВХОДНОЙ параметр и НЕ должен подвергаться модификации!
                        Выходной параметр будет по указателю (или чтобы не происходило копирования объекта)


                        Если есть возможность, надо константить))
                        Сообщение отредактировано: FasterHarder -
                          Есть параметр не указатель (или ссылка, если Плюсы), то он и так входной. И неважно, что там у него за модификаторы.
                          1 пользователей читают эту тему (1 гостей и 0 скрытых пользователей)
                          0 пользователей:


                          Рейтинг@Mail.ru
                          [ Script execution time: 0,6740 ]   [ 15 queries used ]   [ Generated: 18.07.25, 02:24 GMT ]