Где хранятся строковые константы GCC и откуда отображаются эти указатели?
когда я компилирую и запускаю следующую программу C на моей машине Linux x86_64, скомпилированной GCC:
#include <stdio.h>
int main(void)
{
char *p1 = "hello"; // Pointers to strings
char *p2 = "hello"; // Pointers to strings
if (p1 == p2) { // They are equal
printf("equal %p %pn", p1, p2); // equal 0x40064c 0x40064c
// This is always the output on my machine
}
else {
printf("NotEqual %p %pn", p1, p2);
}
}
Я всегда получаю результат как:
равно 0x40064c 0x40064c
Я понимаю, что строки хранятся в постоянной таблице, но адрес слишком низок по сравнению с динамически выделенной памятью.
сравните со следующей программой:
#include <stdio.h>
int main(void)
{
char p1[] = "hello"; // char arrar
char p2[] = "hello"; // char array
if (p1 == p2) {
printf("equal %p %pn", p1, p2);
}
else { // Never equal
printf("NotEqual %p %pn", p1, p2); // NotEqual 0x7fff4b25f720 0x7fff4b25f710
// Different pointers every time
// Pointer values too large
}
}
два указателя не равны, потому что это два массива которым можно манипулировать самостоятельно.
Я хочу знать, как GCC генерирует код для этих двух программ и как они сопоставляются с памятью во время выполнения. Поскольку это будет уже задокументировано не так много раз, любые ссылки на документацию приветствуются.
1 ответов
в обоих случаях компилятор выдает фактические байты строки "hello"
раз, в программы (rodata расшифровывается как только для чтения данных).
они фактически отображаются непосредственно из исполняемого файла в память, что несколько похоже на раздел кода. Вот почему они далеки от динамически распределенных.
затем:
char *p = "hello";
просто инициализирует p
адрес из этих (только для чтения) данных.
И очевидно:
char *q = "hello";
получает тот же адрес. Это называется группировка строк и является необязательной популярной оптимизацией компилятора.
но когда вы пишете:
char p[] = "hello";
он, вероятно, будет генерировать что-то вроде этого:
char p[6];
memcpy(p, "hello", 6);
являясь "hello"
фактически адрес строки пула только для чтения.
вызов memcpy
только для иллюстрации. Он может очень хорошо копировать inline, а не с вызовом функции.
если позже вы сделаете:
char q[] = "hello";
он определит другой массив и другой memcpy()
. Так же данные, но разные адреса.
но где будут находиться эти переменные массива? Ну, это зависит от.
- если они являются локальными, нестатическими, переменными: в стеке.
- если они являются глобальными переменными: тогда они будут в из исполняемый файл, и они будут сохранены там с правильными символами уже там, так что нет
memcpy
необходимо во время выполнения. Что приятно, потому чтоmemcpy
должен быть выполнен доmain
. - если они являются локальными статическими переменными: точно так же, как и с глобальными переменными. Они оба вместе называются
variables of static duration
или что-то подобное.
о ссылках на документацию, извините, я ничего не знаю.
но кому это нужно документация если вы можете сделать эксперименты самостоятельно? Для этого лучший инструмент вокруг objdump
, он может разобрать программу, сбросить разделы данных и многое другое!
я надеюсь, что это ответ на ваши вопросы...