
![]() |
Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
|
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[216.73.216.207] |
![]() |
|
![]() |
|
|
Всем хай! Сходу к делу!
Есть такая придуманная функция: ![]() ![]() char* const F( void ) { char* buf = ( char* )malloc( 100 ); strcpy( buf, "abcdefghijklmnop" ); return buf + 3; } возвращает она КОНСТАНТНЫЙ указатель. Можно было бы вообще так записать, мол const char* const F ..., но пока БЕЗ первого конст. В главной функции есть такой вызов: ![]() ![]() void main( void ) { char* p = NULL; char* s = F(); s = p; // printf( s ); printf( "\n\n" ); system( "pause" ); } да, есть утечка памяти, но на это пока наплевать вообще) меня интересует, почему компилятор пропускает это: ![]() ![]() s = p; ведь вернулся константный указатель. Или дело в том, что объявление s не является константным указателем и нужно так: ![]() ![]() char* const s = F(); да, тогда ругается на строку s = p; Но почему тогда компилятор в принципе позволяет смешивать конст. и не конст указатели, т е почему пропускает эту строку: ![]() ![]() char* s = F(); должен ведь был сообщить, что делается попытка присвоить константный указатель В НЕКОНСТАНТНЫЙ я правильно все описал??) |
![]() |
Сообщ.
#2
,
|
|
Цитата FasterHarder @ Ну ты же можешь написатьменя интересует, почему компилятор пропускает это: ... ![]() ![]() const int x = 123; int y = x; Цитата FasterHarder @ Ну и правильно. Ты пытаешься изменить значение константной переменной. ... тогда ругается на строку s = p; |
Сообщ.
#3
,
|
|
|
Цитата Qraizer @ В чём проблема, если вместо int будет указатель? спс, кажется понял) Цитата Qraizer @ Вот если б у себя был const char*, тогда это были бы указатели на разные типы ![]() ![]() 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 возвращается константный указатель, а присваивается это значение в указатель на константные данные. Все компилируется, все запускается. Но ты ведь, наверное, не на это намекал? еще такой момент: такое легально в Си? ![]() ![]() const char const * const s = ... Добавлено А в целом я случайно наткнулся на возврат константных указателей из функций, т к практически вообще этого нигде нету и в кодах просто возвращают тип* да и все Но мне потребовалось вернуть значение strchr из функции, и компиляция НЕ проходила, какое-то время не мог понять фишку, а потом увидел прототип этой strchr - возвращает константный указатель, правда там перегрузка этой функции и в 1ой версии просто char* без всяких конст возвращается) + тип 1ого параметра конст и простой это я так написал, к слову... |
![]() |
Сообщ.
#4
,
|
|
Цитата FasterHarder @ Не на это. Имелось в виду, если функция будет возвращать const char*, а не chat* const.Но ты ведь, наверное, не на это намекал? Цитата FasterHarder @ Конечно. Первые два const фактически дублируют друг друга, но это не ошибка, const const int, например, тоже не запрещено. Важно, стоит ли const до * или после. До относится к указываемым данным, после – к самому указателю. Могут стоять и в обоих местах, почему нет. еще такой момент: такое легально в Си? |
Сообщ.
#5
,
|
|
|
Цитата Qraizer @ Не на это. Имелось в виду, если функция будет возвращать const char*, а не chat* const. понятно, проверил, действительно так и есть, т е если функция возвращает константу на данные, то ОНА (функция) хочет быть уверена, что за ЕЕ пределами эти данные останутся нетронутыми) Цитата Qraizer @ Конечно. Первые два const фактически дублируют друг друга, но это не ошибка, const const int, например, тоже не запрещено. Важно, стоит ли const до * или после. До относится к указываемым данным, после – к самому указателю. Могут стоять и в обоих местах, почему нет. отлично, понятно кстати, такой вариант значит тоже проходит ![]() ![]() ![]() const const char* const const s = F(); и все компилируется и запускается без проблем... и даже такой ![]() ![]() ![]() ![]() const const char* const const const const s = F(); интересно, не думал, что такое будет пропускать компилятор - ну ладно) Но в целом правило такое, как я понимаю для указателей: достаточно ДВУХ КОНСТ для полной защиты: 1 - ДО *, 2 - ПОСЛЕ *, все остальные КОНСТ избыточные по своей сути... Эти два объявления указателей абсолютно одинаковые с точки зрения константности: ![]() ![]() char const * const s = ... const char* const s = ... но 2ой вариант выглядит намного симпатишнее имхо) --------------------------------- Почти все авторитеты в области программинга люто рекомендуют ставить const где это только возможно, прямо по максимуму. Если есть - надо ставить. Это немного удлиняет все декларации и пр., но дает доп.мощную защиту, как я понимаю. Qraizer, у тебя такое же мнение насчет использования const в коде на языке Си? Т е ставить по максимуму и точка или все-таки...) |
![]() |
Сообщ.
#6
,
|
|
FasterHarder, видишь ли, ты можешь действовать по инструкции и в ус не дуть. И всё будет хорошо почти всегда, и ты можешь всем говорить, что ты крутой, и хорошо всё делаешь и демонстрировать, насколько. А все будут соглашаться. Только есть нюанс: знать, как правильно, и понимать, почему именно так правильно – это две огромнейшие разницы.
Авторитеты советуют дело, но понимаешь ли ты, откуда взялись эти советы? Я нередко вижу что-то типа такого: ![]() ![]() void f(const int x, const char* msg); |
Сообщ.
#7
,
|
|
|
Цитата Qraizer @ и когда спрашиваю, зачем там const, внятного ответа услышать удаётся нечасто. Обычно "ну так все советуют". Ты можешь ответить на этот вопрос касательно этой функции? 1. А что делает это функция F? ) 2. Какова роль этих формальных параметров? const x - блокируют от изменений, чтобы в расчетах было верное значение) const char* msg - это ведь какой-то диалог для пользователя и msg указывает на конст.данные. Чтобы диалог был напечатан правильно и случайно не изменен внутри функции ну, вот мои примерно ответы, но это ты мне не сказал ответы на вопросы 1) и 2). и добавлю, что ставить const советуют авторитеты)) по этой причине не хватает 2ого конст у msg, хотя не факт, что он там нужен... Добавлено 3) Как вызывается эта функция F? (примеры вызовов) |
![]() |
Сообщ.
#8
,
|
|
Чтоб не размазывать, давай так.
Цитата FasterHarder @ Самый последний, но и самый правильный вопрос. Ответ на нет: а какая тебе разница?3) Как вызывается эта функция F? (примеры вызовов) Видишь ли, FasterHarder, прототип функции декларирует её контракт. Абсолютно неважно, как она обращается со своими параметрами внутри, главное, что она декларирует наружу. А наружу она декларирует, что обязуется не менять свои параметры. Мне пофигу, как она внутри устроена, мне важно, чтоб она выполнила свой контракт (конкретно в этом примере неважно, каков он; конечно, в реальном коде я буду знать, что функция делает, иначе зачем же я её зову-то) и чтобы она не нарушила свои обязательства. Поэтому я вполне могу её вызывать как: ![]() ![]() 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); Итого. const в параметрах – это контракт функции. Безусловно важно всем сообщать о том, что не собираешься модифицировать аргументы, если и правда не собираешься. Это особенно важно, когда по указателю передаются структуры, сразу видно, что это просто оптимизация, чтоб структура не копировалась, а не попытка через эту структуру передать обратно результаты работы. И наконец финальный вопрос: зачем у первого параметра const? Мне не пофик ли, что она там внутри с ним делает, если он всё равно пришёл туда по значению? |
Сообщ.
#9
,
|
|
|
Цитата Qraizer @ Поскольку FasterHarder, похоже, утратил интерес к теме, попробую я: как и с локальными переменными, уберечь себя от (не)преднамеренного изменения значения этой переменной внутри реализации функции.наконец финальный вопрос: зачем у первого параметра const? Мне не пофик ли, что она там внутри с ним делает, если он всё равно пришёл туда по значению? Добавление от Qraiser: Видя же подобную ересь во внешнем интерфейсе, я буду скорее склонен подвергнуть сомнению качество реализации её автором, ибо автор тупо не понимает, зачем он оформляет те или иные сущности модели в те или иные сущности кода. |
![]() |
Сообщ.
#10
,
|
|
Ок, Dushevny, а мне-то зачем об этом знать? Это личные трудности автора реализации, на кой они напоказ выставляются в публичном интерфейсе?
Вопрос не в том, как проще автору реализации, он один, а в том, как проще потребителям опубликованного им интерфейса. А их вообще-то вагон, и они смотрят на сие и недоумевают, как им теперь относиться к качеству реализации этой библиотеки, коли её автор... хм, несколько неграмотен. Если только, конечно, автор реализации, не самоудовлетворяется в рамках собственного проекта. Но тогда я этого маразма и не увижу. М-м-м... по идее. Добавлено P.S. Вообще, видеть подобно сродни ![]() ![]() printf("It's - %d - some int value\n", (const int)x); Добавлено P.P.S. Чтоб исключить кривотолки. Прототип предназначен для документирования интерфейса функции. Компилятору и программисту в равной степени. Во внешнем интерфейсе нет места внутренним аспектам реализаций. Этот тезис суть явное следствие предназначения прототипа функции. Видя же подобную ересь во внешнем интерфейсе, я буду скорее склонен подвергнуть сомнению качество реализации её автором, ибо автор тупо не понимает, как и почему именно так он оформляет те или иные сущности реализуемой им мат.модели в те или иные сущности кода. Следовательно я не могу доверять и качеству других аспектов его кододеятельности. |
Сообщ.
#11
,
|
|
|
Цитата Dushevny @ Поскольку FasterHarder, похоже, утратил интерес к теме ты давай не гони тут! ничего я не утратил, просто Qraizer дает много информации для проверок и размышлений... Цитата Qraizer @ И наконец финальный вопрос: зачем у первого параметра const? я сейчас вообще, где только возможно константю копии передаваемых параметров, чтобы ПОДЧЕРКНУТЬ, что это ВХОДНОЙ параметр и НЕ должен подвергаться модификации! Выходной параметр будет по указателю (или чтобы не происходило копирования объекта) Если есть возможность, надо константить)) |
![]() |
Сообщ.
#12
,
|
|
Есть параметр не указатель (или ссылка, если Плюсы), то он и так входной. И неважно, что там у него за модификаторы.
|