Интернирование строк...
От: Alximik509 Россия  
Дата: 30.03.10 15:17
Оценка: :))) :))) :)))
Всем добрый день.

Вопрос на сообразительность.
Что будет выведено после выполнения кода:

int main(int n, char *v)
{    
    char *p1 = "hello";
    char *p2 = "hello";
    p2[0] = '0';    
    if(p1 == p2)
        printf("equal\n");
    else
        printf("not equal\n");
    printf("%s", p1);
    return 0;
}


А теперь главный вопрос.
ПОЧЕМУ???
Re: писать внутрь строковых литералов -- а-та-та!
От: Erop Россия  
Дата: 30.03.10 15:19
Оценка: +4
Здравствуйте, Alximik509, Вы писали:

A>Всем добрый день.


A>Вопрос на сообразительность.

A>Что будет выведено после выполнения кода:

Скорее всего будет выведено "equal\n", а потом ещё пустая строка

A>А теперь главный вопрос.

A>ПОЧЕМУ???

Потому, что писать внутрь строковых литералов -- а-та-та!
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re: Интернирование строк...
От: remark Россия http://www.1024cores.net/
Дата: 30.03.10 15:22
Оценка: +3 :)
Здравствуйте, Alximik509, Вы писали:

A>Вопрос на сообразительность.

A>Что будет выведено после выполнения кода:
A>А теперь главный вопрос.
A>ПОЧЕМУ???

UB+ID


1024cores — all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re: Интернирование строк...
От: pavel.yurchenko Украина  
Дата: 30.03.10 15:22
Оценка:
Здравствуйте, 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>


A>А теперь главный вопрос.

A>ПОЧЕМУ???

Попробовал — падает на

p2[0] = '0';
Re: Интернирование строк...
От: MTimur  
Дата: 30.03.10 15:23
Оценка:
Здравствуйте, Alximik509, Вы писали:

A>Всем добрый день.


A>Вопрос на сообразительность.

A>Что будет выведено после выполнения кода:
A>А теперь главный вопрос.
A>ПОЧЕМУ???

p1 и p2 будут указывать на один кусок памяти?
А здесь не упадет?
A> p2[0] = '0';
Re: Интернирование строк...
От: dabeat_bf Украина http://alexmogurenko.com
Дата: 30.03.10 15:25
Оценка:
Здравствуйте, Alximik509, Вы писали:
A>
A>    p2[0] = '0';    
A>


ub
Re: Интернирование строк...
От: achp  
Дата: 30.03.10 15:25
Оценка: :))) :))
Здравствуйте, Alximik509, Вы писали:

A>Что будет выведено после выполнения кода:


Программист выполнил недопустимую операцию и будет закрыт.
Re: Так и быть.
От: Erop Россия  
Дата: 30.03.10 15:26
Оценка: 1 (1)
Здравствуйте, Alximik509, Вы писали:

A>
A>    char *p1 = "hello";
A>    char *p2 = "hello";
A>


A>ПОЧЕМУ???

Ты, кстати, вроде бы забыл указать язык.
Когда ты пишешь
char *p1 = "hello";
то обычно происходит следующее.
1) Где-то в сегменте статических данных компилятор заводит место под 6 байт и кладёт туда твою строчку.
2) На мето оператора "char *p1 = "hello";" подставляет код инициализации переменной адресом этого места в сегменте статических данных.

Ну когда ты несколько строчек заводишь, большинство компиляторов пытаются сэкономить и если строчки совпадают начинают их переиспользовать. Так что когда ты напишешь
char *p2 = "hello";
компилятор нового места в сегменте статических данных не заведёт, а переиспользует старое.

Ну а дальше сам догадаешься, наверное.

Да, ещё момент. При записи в сегмент статических данных может повезти и память окажется доступна только для чтения. Словишь AV и сразу всё отладишь.
А может не повезти и память позволит в себя писать. Ну и будешь потом долго и занудно выяснять куда у тебя все "hello" в программе пропали

Удачи.

для спасибо тут есть кнопки.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re: Интернирование строк...
От: ДимДимыч Украина http://klug.org.ua
Дата: 30.03.10 15:40
Оценка: :)
Здравствуйте, Alximik509, Вы писали:

A>Что будет выведено после выполнения кода:


В правильной системе должно быть Segmentation Fault.

A>А теперь главный вопрос.

A>ПОЧЕМУ???

Потому что в .rodata секцию писать — ССЗБ.
Обязательно бахнем! И не раз. Весь мир в труху! Но потом. (ДМБ)
Re: Интернирование строк...
От: jazzer Россия Skype: enerjazzer
Дата: 30.03.10 15:51
Оценка:
Здравствуйте, Alximik509, Вы писали:

A>
A>    char *p2 = "hello";
A>    p2[0] = '0';    
A>


A>А теперь главный вопрос.

A>ПОЧЕМУ???

потому что UB — изменение константыа.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[2]: Так и быть.
От: Alximik509 Россия  
Дата: 30.03.10 16:37
Оценка:
Здравствуйте, Erop, Вы писали:

E>Когда ты пишешь
char *p1 = "hello";
то обычно происходит следующее.

E>1) Где-то в сегменте статических данных компилятор заводит место под 6 байт и кладёт туда твою строчку.
E>2) На мето оператора "char *p1 = "hello";" подставляет код инициализации переменной адресом этого места в сегменте статических данных.

E>Ну когда ты несколько строчек заводишь, большинство компиляторов пытаются сэкономить и если строчки совпадают начинают их переиспользовать. Так что когда ты напишешь
char *p2 = "hello";
компилятор нового места в сегменте статических данных не заведёт, а переиспользует старое.


E>Ну а дальше сам догадаешься, наверное.


Все верно! в этом то и фишка.
Конкретно: пробовал на VS2008 и gcc(ведут себя одинаково)
Они действительно объеденяют строки "hello" в одну, и соответственно сравнение указателей дает true во всех случаях.
А вот дальше интересней.
В дебаге:
прога честно падает на "access violatation error" ибо пытается обратиться к защищенной памяти. Все хорошо, все как и ожидалось.
В релизе:
а тут она прекрастно отрабатывает! ни одного варнинга от компилятора!(хоть бы поругался на меня зараза)
а выводит пот что:

equal
hello


Просмотр ассемблерного листинга показал, что компилятор тупо проигнорил присвоение, и при этом даже не заикнулся про это.
Re: Интернирование строк...
От: c-smile Канада http://terrainformatica.com
Дата: 30.03.10 16:40
Оценка:
Здравствуйте, Alximik509, Вы писали:

A>ПОЧЕМУ???


А что именно "ПОЧЕМУ???"

На всякий случай:

http://msdn.microsoft.com/en-us/library/s0s0asdt(VS.71).aspx
Re[3]: Так и быть.
От: Erop Россия  
Дата: 30.03.10 16:41
Оценка:
Здравствуйте, Alximik509, Вы писали:

A>Просмотр ассемблерного листинга показал, что компилятор тупо проигнорил присвоение, и при этом даже не заикнулся про это.


Ну дык имеет право. UB же...
Не предупредил, IMHO, зазря... Но утебя ворнинг может быть где-то в хедерах отключен
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[2]: Интернирование строк...
От: Alximik509 Россия  
Дата: 30.03.10 16:44
Оценка: :))
Здравствуйте, jazzer, Вы писали:

J>потому что UB — изменение константыа.


Заметьте какой тип у переменной. Как бы она не очень константа, да ей присваивается константа, но сама переменная ни ни.

Если писать так..
const char *p2 = "hello";

то нет вопросов, отвалится еще на компиляции.

Кстати, по этому поводу...
почему вот так нельзя
const char *p2 = "hello";
char *p1 = p2;


А вот так можно?
char *p2 = "hello";
Re[4]: Так и быть.
От: Alximik509 Россия  
Дата: 30.03.10 16:45
Оценка:
Здравствуйте, Erop, Вы писали:

E>Не предупредил, IMHO, зазря... Но утебя ворнинг может быть где-то в хедерах отключен


не.. специально выкрутил ворнинг на сколько можно
Re[3]: Так и быть.
От: remark Россия http://www.1024cores.net/
Дата: 30.03.10 17:06
Оценка: 2 (1) +1
Здравствуйте, 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>Просмотр ассемблерного листинга показал, что компилятор тупо проигнорил присвоение, и при этом даже не заикнулся про это.


А о чём ему заикаться? Это не видимое поведение и переменную эту дальше по тексту ты не используешь.


1024cores — all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[3]: Интернирование строк...
От: jazzer Россия Skype: enerjazzer
Дата: 30.03.10 17:30
Оценка: 1 (1)
Здравствуйте, 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.

jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[5]: Так и быть.
От: Erop Россия  
Дата: 30.03.10 17:43
Оценка:
Здравствуйте, Alximik509, Вы писали:

E>>Не предупредил, IMHO, зазря... Но утебя ворнинг может быть где-то в хедерах отключен

A>не.. специально выкрутил ворнинг на сколько можно

против отключения в хедерах это не помогает.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[3]: Интернирование строк...
От: Erop Россия  
Дата: 30.03.10 17:51
Оценка:
Здравствуйте, Alximik509, Вы писали:

A>Заметьте какой тип у переменной. Как бы она не очень константа, да ей присваивается константа, но сама переменная ни ни.


Ну ты таки про какой из двух языков-то спрашиваешь? Видимо про С++?..

A>А вот так можно?

A>
A>char *p2 = "hello";
A>


Для совместимости со старым сишным кодом. Это такое хитрое исключение из правил.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[6]: Так и быть.
От: skeptik_  
Дата: 30.03.10 21:35
Оценка:
Здравствуйте, Erop, Вы писали:

E>Здравствуйте, Alximik509, Вы писали:


E>>>Не предупредил, IMHO, зазря... Но утебя ворнинг может быть где-то в хедерах отключен

A>>не.. специально выкрутил ворнинг на сколько можно

E>против отключения в хедерах это не помогает.


Не, VC++ здесь молчит как партизан. Причём и 2010 тоже.
Re[3]: Так и быть.
От: alexeiz  
Дата: 31.03.10 02:51
Оценка: :)
Здравствуйте, Alximik509, Вы писали:

A>В релизе:

A>а тут она прекрастно отрабатывает! ни одного варнинга от компилятора!(хоть бы поругался на меня зараза)

Наконец-то программа с UB, форматирующая жесткий диск, стала реальностью!
char * command = "format c:";
*command = '\0';
system(command);
Re[4]: Так и быть.
От: remark Россия http://www.1024cores.net/
Дата: 31.03.10 05:06
Оценка:
Здравствуйте, alexeiz, Вы писали:

A>>В релизе:

A>>а тут она прекрастно отрабатывает! ни одного варнинга от компилятора!(хоть бы поругался на меня зараза)

A>Наконец-то программа с UB, форматирующая жесткий диск, стала реальностью!

A>
A>char * command = "format c:";
A>*command = '\0';
A>system(command);
A>


Хммм... там-то строчка после записи не использовалась, а тут используется. Почему компилятор будет опускать эту запись? Пробовал запускать?


1024cores — all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[5]: Так и быть.
От: Alximik509 Россия  
Дата: 31.03.10 08:06
Оценка:
Здравствуйте, remark, Вы писали:

R>Здравствуйте, alexeiz, Вы писали:


A>>>В релизе:

A>>>а тут она прекрастно отрабатывает! ни одного варнинга от компилятора!(хоть бы поругался на меня зараза)

A>>Наконец-то программа с UB, форматирующая жесткий диск, стала реальностью!

A>>
A>>char * command = "format c:";
A>>*command = '\0';
A>>system(command);
A>>


R>Хммм... там-то строчка после записи не использовалась, а тут используется. Почему компилятор будет опускать эту запись? Пробовал запускать?


R>


Пробовали.. компилятор просто игнорит любое такое присвоение.
Более того, он даже игнорит вызовы функций с такими аргументами.

Например вот такую функцию он не вызывает.

void foo(char *p)
{    
    for(int i=0 ;i < 10; i++)
    {
    
        *p = '0';
        p++;
    }
    *p = '\0';
}


А вот если так. то вызывает. и получаем ошибку в рантайме

void foo(char *p)
{    
    for(int i=0 ;i < 10; i++)
    {
    
        *p = '0';
        p++;
    }
    *p = '\0';
    printf("%s", p);
}


Вообще очень странное поведение
Re[6]: Так и быть.
От: remark Россия http://www.1024cores.net/
Дата: 31.03.10 08:10
Оценка:
Здравствуйте, Alximik509, Вы писали:

R>>Хммм... там-то строчка после записи не использовалась, а тут используется. Почему компилятор будет опускать эту запись? Пробовал запускать?


R>>


A>Пробовали.. компилятор просто игнорит любое такое присвоение.


Игнорит он в твоём примере, где данные не используются после записи. А тут-то совсем другая ситуация.

A>Более того, он даже игнорит вызовы функций с такими аргументами.


A>Например вот такую функцию он не вызывает.


Я об этом и говорю. Если код не производит никакого видимого поведения, то зачем его генерировать? Тут-то другая ситуация.


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[7]: Так и быть.
От: Alximik509 Россия  
Дата: 31.03.10 09:08
Оценка:
Здравствуйте, remark, Вы писали:

R>Я об этом и говорю. Если код не производит никакого видимого поведения, то зачем его генерировать? Тут-то другая ситуация.


R>


не.. даже если так

char * command = "format c:";
*command = '\0';
system(command);


все равно строчку он не будет пытаться менять
Re[8]: Так и быть.
От: remark Россия http://www.1024cores.net/
Дата: 31.03.10 09:16
Оценка:
Здравствуйте, Alximik509, Вы писали:

A>не.. даже если так


A>
A>char * command = "format c:";
A>*command = '\0';
A>system(command);
A>


A>все равно строчку он не будет пытаться менять


Ну тогда одно слово — UB


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re: Кстати, хочу также темы
От: achp  
Дата: 31.03.10 11:10
Оценка: :)
…про пленение, капитуляцию и нейтралитет строк.
Re[2]: Так и быть.
От: Pavel Dvorkin Россия  
Дата: 02.04.10 13:37
Оценка: :)
Здравствуйте, 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";
With best regards
Pavel Dvorkin
Re[3]: 2 Egor
От: Pavel Dvorkin Россия  
Дата: 02.04.10 16:52
Оценка:
Над чем смеемся ? Над компилятором ?
With best regards
Pavel Dvorkin
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.