Здравствуйте, Alximik509, Вы писали:
A>Всем добрый день.
A>Вопрос на сообразительность. A>Что будет выведено после выполнения кода:
Скорее всего будет выведено "equal\n", а потом ещё пустая строка
A>А теперь главный вопрос. A>ПОЧЕМУ???
Потому, что писать внутрь строковых литералов -- а-та-та!
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Alximik509, Вы писали:
A>Всем добрый день.
A>Вопрос на сообразительность. A>Что будет выведено после выполнения кода:
A>
A>int main(int n, char *v)
A>{
A> char *p1 = "hello";
A> char *p2 = "hello";
A> p2[0] = '0';
A> if(p1 == p2)
A> printf("equal\n");
A> else
A> printf("not equal\n");
A> printf("%s", p1);
A> return 0;
A>}
A>
Здравствуйте, Alximik509, Вы писали:
A>Всем добрый день.
A>Вопрос на сообразительность. A>Что будет выведено после выполнения кода: A>А теперь главный вопрос. A>ПОЧЕМУ???
p1 и p2 будут указывать на один кусок памяти?
А здесь не упадет? A> p2[0] = '0';
A>ПОЧЕМУ???
Ты, кстати, вроде бы забыл указать язык.
Когда ты пишешь
char *p1 = "hello";
то обычно происходит следующее.
1) Где-то в сегменте статических данных компилятор заводит место под 6 байт и кладёт туда твою строчку.
2) На мето оператора "char *p1 = "hello";" подставляет код инициализации переменной адресом этого места в сегменте статических данных.
Ну когда ты несколько строчек заводишь, большинство компиляторов пытаются сэкономить и если строчки совпадают начинают их переиспользовать. Так что когда ты напишешь
char *p2 = "hello";
компилятор нового места в сегменте статических данных не заведёт, а переиспользует старое.
Ну а дальше сам догадаешься, наверное.
Да, ещё момент. При записи в сегмент статических данных может повезти и память окажется доступна только для чтения. Словишь AV и сразу всё отладишь.
А может не повезти и память позволит в себя писать. Ну и будешь потом долго и занудно выяснять куда у тебя все "hello" в программе пропали
Удачи.
для спасибо тут есть кнопки.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
то обычно происходит следующее. E>1) Где-то в сегменте статических данных компилятор заводит место под 6 байт и кладёт туда твою строчку. E>2) На мето оператора "char *p1 = "hello";" подставляет код инициализации переменной адресом этого места в сегменте статических данных.
E>Ну когда ты несколько строчек заводишь, большинство компиляторов пытаются сэкономить и если строчки совпадают начинают их переиспользовать. Так что когда ты напишешь
char *p2 = "hello";
компилятор нового места в сегменте статических данных не заведёт, а переиспользует старое.
E>Ну а дальше сам догадаешься, наверное.
Все верно! в этом то и фишка.
Конкретно: пробовал на VS2008 и gcc(ведут себя одинаково)
Они действительно объеденяют строки "hello" в одну, и соответственно сравнение указателей дает true во всех случаях.
А вот дальше интересней.
В дебаге:
прога честно падает на "access violatation error" ибо пытается обратиться к защищенной памяти. Все хорошо, все как и ожидалось.
В релизе:
а тут она прекрастно отрабатывает! ни одного варнинга от компилятора!(хоть бы поругался на меня зараза)
а выводит пот что:
equal
hello
Просмотр ассемблерного листинга показал, что компилятор тупо проигнорил присвоение, и при этом даже не заикнулся про это.
Здравствуйте, Alximik509, Вы писали:
A>Просмотр ассемблерного листинга показал, что компилятор тупо проигнорил присвоение, и при этом даже не заикнулся про это.
Ну дык имеет право. UB же...
Не предупредил, IMHO, зазря... Но утебя ворнинг может быть где-то в хедерах отключен
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Alximik509, Вы писали:
A>Все верно! в этом то и фишка. A>Конкретно: пробовал на VS2008 и gcc(ведут себя одинаково) A>Они действительно объеденяют строки "hello" в одну, и соответственно сравнение указателей дает true во всех случаях.
Выключи в студии опцию Enable String Polling (/GF)
A>А вот дальше интересней. A>В дебаге: A>прога честно падает на "access violatation error" ибо пытается обратиться к защищенной памяти. Все хорошо, все как и ожидалось. A>В релизе: A>а тут она прекрастно отрабатывает! ни одного варнинга от компилятора!(хоть бы поругался на меня зараза)
Конвертация строковых литералов из char const* в char* — это наследние С.
A>а выводит пот что: A> A>equal A>hello A>
A>Просмотр ассемблерного листинга показал, что компилятор тупо проигнорил присвоение, и при этом даже не заикнулся про это.
А о чём ему заикаться? Это не видимое поведение и переменную эту дальше по тексту ты не используешь.
Здравствуйте, Alximik509, Вы писали:
A>Здравствуйте, jazzer, Вы писали:
J>>потому что UB — изменение константыа.
A>Заметьте какой тип у переменной. Как бы она не очень константа, да ей присваивается константа, но сама переменная ни ни.
константа в данном случае — это массив со строкой, а не указатель на него.
A>А вот так можно? A>
A>char *p2 = "hello";
A>
Потому что для этого конкретного преобразования (литерал в неконстантный указатель) есть специальный пункт в стандарте.
Для совместимости с классическими функциями Си типа strlen.
Коего тут есть поклонники.
4.2/2
A string literal (2.13.4) that is not a wide string literal can be converted to an rvalue of type “pointer to char”; a wide string literal can be converted to an rvalue of type “pointer to wchar_t”. In either case, the result is a pointer to the first element of the array. This conversion is considered only when there is an explicit appropriate pointer target type, and not when there is a general need to convert from an lvalue to an rvalue. [Note: this conversion is deprecated. See Annex D. ] For the purpose of ranking in overload resolution (13.3.3.1.1), this conversion is considered an array-to-pointer conversion followed by a qualification conversion (4.4). [Example: "abc" is converted to “pointer to const char” as an array-to-pointer conversion, and then to “pointer to char” as a qualification conversion. ]
Ну и
D.4 Implicit conversion from const strings [depr.string]
1 The implicit conversion from const to non-const qualification for string literals (4.2) is deprecated.
Здравствуйте, Alximik509, Вы писали:
E>>Не предупредил, IMHO, зазря... Но утебя ворнинг может быть где-то в хедерах отключен A>не.. специально выкрутил ворнинг на сколько можно
против отключения в хедерах это не помогает.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Alximik509, Вы писали:
A>Заметьте какой тип у переменной. Как бы она не очень константа, да ей присваивается константа, но сама переменная ни ни.
Ну ты таки про какой из двух языков-то спрашиваешь? Видимо про С++?..
A>А вот так можно? A>
A>char *p2 = "hello";
A>
Для совместимости со старым сишным кодом. Это такое хитрое исключение из правил.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, Alximik509, Вы писали:
E>>>Не предупредил, IMHO, зазря... Но утебя ворнинг может быть где-то в хедерах отключен A>>не.. специально выкрутил ворнинг на сколько можно
E>против отключения в хедерах это не помогает.
Не, VC++ здесь молчит как партизан. Причём и 2010 тоже.