Здравствуйте, 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 тоже.
Здравствуйте, Alximik509, Вы писали:
A>В релизе: A>а тут она прекрастно отрабатывает! ни одного варнинга от компилятора!(хоть бы поругался на меня зараза)
Наконец-то программа с UB, форматирующая жесткий диск, стала реальностью!
Здравствуйте, alexeiz, Вы писали:
A>>В релизе: A>>а тут она прекрастно отрабатывает! ни одного варнинга от компилятора!(хоть бы поругался на меня зараза)
A>Наконец-то программа с UB, форматирующая жесткий диск, стала реальностью! A>
Здравствуйте, remark, Вы писали:
R>Здравствуйте, alexeiz, Вы писали:
A>>>В релизе: A>>>а тут она прекрастно отрабатывает! ни одного варнинга от компилятора!(хоть бы поругался на меня зараза)
A>>Наконец-то программа с UB, форматирующая жесткий диск, стала реальностью! A>>
Здравствуйте, Alximik509, Вы писали:
R>>Хммм... там-то строчка после записи не использовалась, а тут используется. Почему компилятор будет опускать эту запись? Пробовал запускать?
R>>
A>Пробовали.. компилятор просто игнорит любое такое присвоение.
Игнорит он в твоём примере, где данные не используются после записи. А тут-то совсем другая ситуация.
A>Более того, он даже игнорит вызовы функций с такими аргументами.
A>Например вот такую функцию он не вызывает.
Я об этом и говорю. Если код не производит никакого видимого поведения, то зачем его генерировать? Тут-то другая ситуация.
Здравствуйте, remark, Вы писали:
R>Я об этом и говорю. Если код не производит никакого видимого поведения, то зачем его генерировать? Тут-то другая ситуация.
R>
Здравствуйте, Erop, Вы писали:
E>Ну когда ты несколько строчек заводишь, большинство компиляторов пытаются сэкономить и если строчки совпадают начинают их переиспользовать. Так что когда ты напишешь
char *p2 = "hello";
компилятор нового места в сегменте статических данных не заведёт, а переиспользует старое.
/GF (Eliminate Duplicate Strings)
See Also Send Feedback
Enables the compiler to create a single copy of identical strings in the program image and in memory during execution, resulting in smaller programs, an optimization called string pooling.
/GF
Remarks
/GF pools strings as read-only.
If you use /GF, the operating system does not swap the string portion of memory and can read the strings back from the image file. If you try to modify strings under /GF, an application error occurs.
String pooling allows what were intended as multiple pointers to multiple buffers to be as multiple pointers to a single buffer. In the following code, s and t are initialized with the same string. String pooling causes them to point to the same memory:
Copy Code
char *s = "This is a character buffer";
char *t = "This is a character buffer";