Arlleex 178 8 сентября, 2020 Опубликовано 8 сентября, 2020 · Жалоба Так это наоборот прекрасно - компилятор заставляет лишний раз подумать о том, что ты делаешь. Ну а const как бы лишний раз напоминает, что за объект тот самый идентификатор. Плюс, достаточно часто функции требуют указатель (обычный), а мы туда передаем, например, строку. Компилятор тоже будет выдавать предупреждение, однако этот момент мы умалчиваем, видимо... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
razrab83 21 9 сентября, 2020 Опубликовано 9 сентября, 2020 (изменено) · Жалоба 8 часов назад, Arlleex сказал: Плюс, достаточно часто функции требуют указатель (обычный) такого не бывает, либо это говнокод. Например функции (пусть будет некое API, реализация скрыта в библиотеках) void func1(int *value); void func2(const int *value); если я вызову func2 и передам туда (обычный или конст) указатель, я буду 100% уверен в том, что мои данные не изменяться. Такой аргумент "const int *value" с языка с/с++ можно перевести на русский как "уважаемый программист, при использовании этого метода, будьте уверены, что ваши данные останутся неизменными". В func1 данные могут быть модифицированы. Если вы пишете свою функцию и в аргументах передаете указатель или ссылку, и этот метод не должен менять данные по * или &, то всегда ставьте const. Это убережет от ошибок реализации метода, а также будет в дальнейшем будет легче пользоваться методом. 8 часов назад, Arlleex сказал: функции требуют указатель (обычный), а мы туда передаем, например, строку. Компилятор тоже будет выдавать предупреждение, однако этот момент мы умалчиваем, видимо... если строка константная, ворнинга не будет, компилятор даст ошибку и не соберёт код. если строка не конст, то ни каких ворнингов не будет. Изменено 9 сентября, 2020 пользователем razrab83 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 234 9 сентября, 2020 Опубликовано 9 сентября, 2020 · Жалоба 5 часов назад, razrab83 сказал: если строка константная, ворнинга не будет, компилятор даст ошибку и не соберёт код. если строка не конст, то ни каких ворнингов не будет. Вы бы сперва попробовали, прежде чем говорить. Arlleex сказал правильно: Никаких ни ошибок ни варнингов не будет - компилятор молча проглотит и прожуёт такой код. Это один из недостатков, зачем-то тянущийся в си-компиляторах с древних времён. Видимо для некой мифической совместимости со старым кривым кодом. Обсуждали этот вопрос уже тут на форуме как-то. Не так давно.... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 178 9 сентября, 2020 Опубликовано 9 сентября, 2020 · Жалоба 1 час назад, jcxz сказал: Вы бы сперва попробовали, прежде чем говорить. Arlleex сказал правильно... Скорее, наоборот - @razrab83 прав. Но частично. Например, смотрю поведение в Keil uVision (CLang). void func1(char *p) {} void func2(const char *) {} ... char str1[] = "String"; const char str2[] = "String"; func1("String"); // ok func2("String"); // ok func1(str1); // ok func1(str2); // warning: passing 'const char [4]' to parameter of type 'char *' discards qualifiers func2(str1); // ok func2(str2); // ok Для меня (по крайней мере) тут все логично, кроме одного. ИМХО, func1("String") тоже должна давать warning, но этого не происходит. Полезные ссылки: №1, №2. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 234 9 сентября, 2020 Опубликовано 9 сентября, 2020 · Жалоба 30 минут назад, Arlleex сказал: Скорее, наоборот - @razrab83 прав. Но частично. Ну а где-ж прав? В вашем же примере func1("String") по уму должно выдать ошибку. Т.к. "String" - константа? По факту - константа. Ибо находится в RO-секции. Но почему-то при явной передаче аргументом функции считается типом "char *". Цитата Для меня (по крайней мере) тут все логично, кроме одного. ИМХО, func1("String") тоже должна давать warning, но этого не происходит. IAR на такое вообще выдаёт error, а не warning. Error[Pe167]: argument of type "char const *" is incompatible with parameter of type "char *" D:\...\main.cpp 415 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
razrab83 21 9 сентября, 2020 Опубликовано 9 сентября, 2020 (изменено) · Жалоба 1 час назад, jcxz сказал: Вы бы сперва попробовали, прежде чем говорить. Arlleex сказал правильно: Никаких ни ошибок ни варнингов не будет - компилятор молча проглотит и прожуёт такой код. в чем прав и какой код? void func1(char *p){} //со слов Arlleex "достаточно часто функции требуют указатель (обычный)" const char *str = "asd"; func(str); //тут error. со слов Arlleex " а мы туда передаем, например, строку." Цитата IAR на такое вообще выдаёт error вот об это я и говорю. Изменено 9 сентября, 2020 пользователем razrab83 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Eddy_Em 1 9 сентября, 2020 Опубликовано 9 сентября, 2020 · Жалоба 49 minutes ago, jcxz said: Т.к. "String" - константа? По факту - константа. Ибо находится в RO-секции. Но почему-то при явной передаче аргументом функции считается типом "char *". Ну так компилируйте с флагами -Wall -Werror -Wextra, и все предупреждения будут расцениваться как ошибки. А вообще, gcc обычно предупреждает, если пытаешься константу отправить в функцию, где перед аргументом const отсутствует. Вот наоборот — запросто. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 234 9 сентября, 2020 Опубликовано 9 сентября, 2020 · Жалоба 1 час назад, Eddy_Em сказал: Ну так компилируйте с флагами -Wall -Werror -Wextra, и все предупреждения будут расцениваться как ошибки. Причём тут это??? Вы не поняли предмета обсуждения. 1 час назад, razrab83 сказал: func(str); //тут error. со слов Arlleex " а мы туда передаем, например, строку." А теперь попробуйте func("str"); Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Eddy_Em 1 9 сентября, 2020 Опубликовано 9 сентября, 2020 · Жалоба 25 minutes ago, jcxz said: А теперь попробуйте func("str"); cat 1.c #include <stdio.h> void p(char *s){ printf("str: %s\n", s); } int main(){ const char *x = "hello"; char *y = "test"; p(x); p(y); p("String"); return 0; } И действительно: gcc 1.c 1.c: В функции <<main>>: 1.c:10:4: предупреждение: передача аргумента 1 <<p>> отменяет квалификатор <<const>> указуемого типа [-Wdiscarded-qualifiers] 10 | p(x); | ^ 1.c:3:14: замечание: ожидался тип <<char *>>, но аргумент имеет тип <<const char *>> 3 | void p(char *s){ | ~~~~~~^ Т.е. строка, хоть и является фактически const char*, рассматривается gcc как char (эквивалентно p(y))! И нужно явно писать p((const char*)"String"); чтобы получить предупреждение. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
razrab83 21 10 сентября, 2020 Опубликовано 10 сентября, 2020 (изменено) · Жалоба 15 часов назад, jcxz сказал: А теперь попробуйте func("str"); Цитата "C:\testIar\main.c",8 Warning[Pe2464]: conversion from a string literal to "char *" is deprecated это иар из коробки в идэ выдал. с++ тоже дает ворнинг на такой код Цитата main.cpp:22:14: warning: ISO C++ forbids converting a string constant to ‘char*’ gcc молча съел. но gcc с ключом -Wwrite-strings выдал Цитата ../Src/main.c:33:8: warning: passing argument 1 of 'func1' discards 'const' qualifier from pointer target type func1("asdf"); ^~~~~~ ../Src/main.c:24:5: note: expected 'char *' but argument is of type 'const char *' int func1( char *a) ps да, си, в отличии от с++, может пропустить "asdf" (но не const char *str = "asdf"). Лишний раз задаюсь риторическим вопросом - зачем нужен си? С++ более строг. Если даже не любишь(не знаешь) ооп, не нужны классы, шаблоны, stl и прочие плюшки... пиши код аля си стайл с любимым goto, но собирай его сипипишным компилятором. Изменено 10 сентября, 2020 пользователем razrab83 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Eddy_Em 1 10 сентября, 2020 Опубликовано 10 сентября, 2020 · Жалоба C хорош тем, что даёт полную свободу выстрелить себе в ногу! За это я так люблю этот ЯП. Остальные же в той или иной степени огораживают, что есть крайне плохо!!! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 234 10 сентября, 2020 Опубликовано 10 сентября, 2020 · Жалоба 4 часа назад, razrab83 сказал: это иар из коробки в идэ выдал. Какая версия и с какими ключами? Мой 7.80.4 не выдаёт ничего. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
one_eight_seven 6 10 сентября, 2020 Опубликовано 10 сентября, 2020 · Жалоба 20 hours ago, Eddy_Em said: Т.е. строка, хоть и является фактически const char*, рассматривается gcc как char (эквивалентно p(y))! Нет, она фактически не является const char *, она является изменяемым массивом символов (mutable char array), т.е. аналогом char str[] = "String" И между char* и char[] огромная разница. Например, вот это вызовет Segfault: char * p = "inmutable"; p[1] = 'm'; А вот это прекрасно исполнится: char s[] = "chang me"; s[5] = 'e'; Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 234 10 сентября, 2020 Опубликовано 10 сентября, 2020 · Жалоба 12 минут назад, one_eight_seven сказал: Например, вот это вызовет Segfault: char * p = "inmutable"; p[1] = 'm'; Вот это-то и плохо. По уму тут компилятор должен выдать warning/error. На первую строчку. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
one_eight_seven 6 10 сентября, 2020 Опубликовано 10 сентября, 2020 · Жалоба 9 minutes ago, jcxz said: Вот это-то и плохо. По уму тут компилятор должен выдать warning/error. Не согласен. Это не работа компилятора. Это работа статического анализатора кода, lint или чего-то в этом роде. В первом случае указатель прямо указывает на string literal. Во втором случае создаётся массив на стеке, который инициализируется из string literal'а, и указатель s не указывает на оригинальный литерал (который неизменяемый). Но в C, действительно много плохого. Например, вот эти вот неявные приведения типов. Я согласен, что нет ничего плохого, в том, чтобы повысить строгость типизации и повысить тем самым безопасность типов. Например, ключами компиляции. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться