C оптимизация строковых литералов

только что проверял следующее в GDB:

char *a[] = {"one","two","three","four"};
char *b[] = {"one","two","three","four"};
char *c[] = {"two","three","four","five"};
char *d[] = {"one","three","four","six"};

и я получаю следующее:

(gdb) p a
$17 = {0x80961a4 "one", 0x80961a8 "two", 0x80961ac "three", 0x80961b2 "four"}
(gdb) p b
$18 = {0x80961a4 "one", 0x80961a8 "two", 0x80961ac "three", 0x80961b2 "four"}
(gdb) p c
$19 = {0x80961a8 "two", 0x80961ac "three", 0x80961b2 "four", 0x80961b7 "five"}
(gdb) p d
$20 = {0x80961a4 "one", 0x80961ac "three", 0x80961b2 "four", 0x80961bc "six"}

Я действительно удивлен, что строковые указатели одинаковы для эквивалентных слов. Я бы подумал, что каждая строка будет выделена собственная память в стеке независимо от того, была ли она такой же, как строка в другом массиве.

Это пример какой-то оптимизации компилятора или это стандартное поведение для объявления строк такого рода?

 Jack09 июл. 2012 г., 19:27
Да. Это пример оптимизации компилятора.
 bph09 июл. 2012 г., 19:10
да - это локальные переменные автоматической длительности, объявленные внутри функции, поэтому в стеке
 AnT09 июл. 2012 г., 19:07
Откуда взялся «стек» даже откуда в этом вопросе? Если вы объявилиa, b, c а такжеd как локальные переменные, вы должны сказать это в своем вопросе.
 The Paramagnetic Croissant03 дек. 2014 г., 09:14
"Я бы подумал, что каждой строке будет выделена своя память в стеке" - "в стеке"? Сstatic срок хранения? Как?
 legends2k03 дек. 2014 г., 09:14

Ответы на вопрос(2)

a, b, c а такжеd объявлены как локальные переменные, что является причиной ваших ожиданий, связанных со стеком.)

Строковые литералы в C имеют статическую длительность хранения. Они никогда не размещаются «в стеке». Они всегда размещаются в глобальной / статической памяти и живут «навсегда», то есть до тех пор, пока выполняется программа.

Вашa, b, c а такжеd массивы были размещены в стеке. Указатели, хранящиеся в этих массивах, указывают на статическую память. В этих обстоятельствах нет ничего необычного в том, что указатели идентичных слов идентичны.

Будет ли компилятор объединять идентичные литералы в один, зависит от компилятора. Некоторые компиляторы даже имеют опцию, которая управляет этим поведением. Строковые литералы всегда доступны только для чтения (вот почему лучше использоватьconst char * введите для ваших массивов), поэтому не имеет большого значения, будут ли они объединены или нет, пока вы не начнете полагаться на фактические значения указателя.

Постскриптум Просто из любопытства: даже если эти строковые литералы были размещены в стеке, почему вы ожидаете, что идентичные литералы будут "инстанцированы"? больше чем единожды?

 bph09 июл. 2012 г., 19:07
отличный материал - это очень помогло моему пониманию, не полностью поняв материал строкового литерала и связанную с ним продолжительность хранения - я неправильно думал о строках как о просто локальных переменных (автоматически) в стеке
 09 июл. 2012 г., 19:12
Ничто из того, что мне известно, не говорит о том, что две (или более) ссылки на один и тот же строковый литералmust разрешить в ту же область памяти. Компилятор может (и некоторые делают) выделять память для каждого строкового литерала, даже если некоторые являются «дубликатами». Смотрите & quot; объединение строк & quot; упомянутый @Josh.
Решение Вопроса

icrosoft, но не в GCC. Если вы отключите пул строк в MSVC, то «тот же» строки в разных массивах будут дублироваться и иметь разные адреса памяти, и поэтому они будут занимать дополнительные (ненужные) 50 или около того байтов ваших статических данных.

РЕДАКТИРОВАТЬ: GCC до версии 4.0 была опция,-fwritable-strings который отключил объединение строк. Эффект этого параметра был двояким: он позволял перезаписывать строковые литералы и отключал объединение строк. Итак, в вашем коде установка этого флага позволит несколько опасный код

/* Overwrite the first string in a, so that it reads 'xne'.  Does not */ 
/* affect the instances of the string "one" in b or d */
*a[0] = 'x';
 09 окт. 2014 г., 16:20
@ dbrank0 обратите внимание, чтоgcc no longer supports fwritabe-sringsбыло бы идеально добавить обе эти заметки к вашему ответу.
 23 нояб. 2018 г., 18:01
@ShafikYaghmour - отредактировано (4 года спустя :)
 20 янв. 2014 г., 14:25
В GCC (по крайней мере, 4.7) ключ для отключения пула - это -fno-merge-constants.

Ваш ответ на вопрос