Действительно ли печатается адрес строки в C
У меня есть 2 вопроса... (Я изучаю C, и это могут быть глупые вопросы. Извинения)
-
Как Как объявить строки в C и в большинстве книг, они всегда говорят, объявляя строку, даже если вы выделяете память, говоря
char p2[] = "String";
Мой вопрос: есть ли смысл объявлять строку?
помещаются в область только для чтения, а затем копируются в массив. Действительно ли в C печатать адрес строки, как это?
printf("%p\n", &"Hello There"); // I tried, it prints some address
и делая это
printf("%p\n", &"Hello There");
printf("%p\n", &"Hello There");
он печатает тот же адрес. что такое чувство, он должен печатать другой адрес. Здесь компилятор делает некоторую оптимизацию?
Ответы
Ответ 1
C стандарт, §6.4.5 Строковые литералы, говорит:
Неизвестно, являются ли эти массивы различными, если их элементы имеют соответствующие значения.
Таким образом, два строковых литерала с одним и тем же содержимым могут обозначать один и тот же массив, и печать их адресов дает одно и то же значение указателя дважды. Это решение для компилятора и компоновщика; когда я компилирую следующую программу как два отдельных модуля...
// main.c
#include <stdio.h>
extern void print_foo_addr(void);
int main()
{
printf("%p\n", &"foo");
print_foo_addr();
return 0;
}
и
// printfoo.c
#include <stdio.h>
void print_foo_addr()
{
printf("%p\n", &"foo");
}
... тогда я получаю два разных значения указателя (GCC 4.7.3 в Linux), но когда я поместил определение для print_foo_addr
в main.c
, я получаю одно и то же значение дважды. Так что да, это оптимизация, которая явно разрешена стандартом, но GCC по крайней мере выполняет эту оптимизацию только для каждого модуля.
Ответ 2
Это специально разрешено стандартом C.
6.4.5p5-6:
В фазу 7 перевода байта или код нулевого значения добавляется к каждой многобайтовой последовательности символов, которая получается из строкового литерала или литералов. Последовательность многобайтовых символов затем используется для инициализации массива статической продолжительности хранения и длины, достаточной для того, чтобы содержать последовательность....
Неизвестно, являются ли эти массивы различными, если их элементы имеют соответствующие значения.
Ответ 3
"Hello There"
- строковый литерал, и он будет доступен в строковой таблице (причина получения того же адреса для "Hello There"
в printf
).
Когда вы делаете
char p2[] = "String";
будет выделена память, а "String" будет скопирована на вновь созданную память. Но
char * p3 = "String";
будет указывать на раздел только для чтения. i.e строка таблицы.
В этом случае, если вы печатаете p3
и &"String"
будет одинаковым.
Если вы печатаете p2
и &"String"
, будет напечатан другой адрес. Поскольку p2
- адрес стека.
Ответ 4
Литеральные строки помещаются в специальный раздел, который следует читать только. Кроме того, если вы используете один и тот же строковый литерал в нескольких местах, тогда компилятор обычно может создавать только один экземпляр этой строки. Вот почему вы видите тот же адрес в этом примере:
printf("%p\n", &"Hello There");
printf("%p\n", &"Hello There");
Однако вы не можете полагаться на это, потому что это оптимизация компилятора, которая может или не может произойти.