Как реализована постоянная память в C? - PullRequest
22 голосов
/ 10 ноября 2009

Я слышал, что в C, если я делаю

char *s = "hello world". 

«Привет, мир» фактически хранится в постоянной памяти.

Я не очень хорошо разбираюсь в памяти только для чтения. Какое объяснение? Это как флаг компилятору, который говорит компилятору не писать в этот раздел?

Ответы [ 7 ]

31 голосов
/ 10 ноября 2009

Это не особенность языка C , а особенность совместной работы компилятора / компоновщика и операционной системы.

Когда вы компилируете такой код, происходит следующее:

  • Компилятор поместит строку в раздел данных только для чтения.

  • Компоновщик собирает все данные в таких разделах только для чтения и помещает их в один сегмент. Этот сегмент находится в исполняемом файле и помечен атрибутом «только для чтения».

  • Теперь идет исполняемый файл операционной системы. Он загружает исполняемый файл (или отображает его в памяти, чтобы быть более точным). После этого загрузчик просматривает разделы и устанавливает права доступа для каждого сегмента. Для сегмента данных только для чтения он, скорее всего, отключит выполнение кода и доступ на запись. Код (например, ваши функции) получает права на выполнение, но не имеет права на запись. Обычные данные, такие как статические переменные, получают права на чтение и запись и так далее ...

Вот как это делают современные операционные системы.

Как уже говорилось, это не особенность языка Си. Например, если вы скомпилируете ту же проблему для DOS, программа запустится, но защита от записи будет невозможна, поскольку загрузчик DOS не знает о разделах, доступных только для чтения.

6 голосов
/ 10 ноября 2009

Исполняемые файлы содержат две части: раздел .data, содержащий глобальные переменные, и раздел .text, содержащий фактический машинный код.

Строки помещаются в раздел .data. Что делает C, когда видит «Hello world», это помещает строку «Hello world» в сам исполняемый файл и заменяет экземпляр «Hello world» в программе на адрес, по которому эта строка загружается.

Сказав это, я не уверен, почему это только для чтения - теоретически программа должна иметь возможность изменять свою собственную память ..

4 голосов
/ 10 ноября 2009

Истинная постоянная память реализуется подсистемой памяти ОС. ОС может пометить определенные страницы только для чтения.

В двоичном коде компилятор может сообщить ОС, какие части исполняемого файла должны быть размещены на страницах памяти только для чтения и страниц памяти для чтения и записи.

2 голосов
/ 10 ноября 2009

Пример того, как это сделать в Linux, можно найти на странице 179 из Advanced Linux Programming , написанной Марком Митчеллом, Джеффри Олхэмом и Алексом Самуэлем.

1 голос
/ 08 июля 2016

когда пишешь char s[10]="sneha"; Вы выделяете 10 байтов дискового пространства (не память, память появляется только при выполнении вашей программы) в вашем объектном файле Это статическое распределение памяти (во время компиляции).

Но когда вы пишете char *s="sneha";, вы не выделяете место для хранения "sneha". Он будет храниться в разделе только для чтения. Но указатель s хранится в другом разделе в зависимости от того, где он объявлен. Но он указывает на ЧТЕНИЕ ТОЛЬКО ДАННЫХ "sneha". Поэтому, если вы попытаетесь написать на нем, вы получите ошибку сегментации.

Например:

char *s = "sneha";
s[1] = 'N'; 
printf("%s",s);  // you expecting output sNeha, 
                 // but you get a seg fault since it is READ ONLY DATA 
1 голос
/ 10 ноября 2009

Как уже упоминали другие, то, хранится ли содержимое константных строк в постоянной памяти, определяется операционной системой, компилятором и архитектурой чипа.

Точнее, стандарт C указывает, что строки в кавычках считаются имеющими тип "const char []" (или слова на этот счет, у меня нет стандарта под рукой).

Любой код, который пытается изменить содержимое такой строки, вызывает неопределенное поведение. Это означает, что буквально все может произойти в этот момент, и поставщику компилятора даже не требуется документировать, что может произойти.

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

В общем, компилятор не позволяет вам изменять содержимое переменных «const», поэтому вы можете считать «const» значением «только для чтения» в большинстве случаев. К сожалению, есть специальное исключение для char * и const char *, в основном по историческим причинам. Это означает, что код такой:

char *x = "Hello, World";
*x = 'h';

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

0 голосов
/ 10 ноября 2009

Вы можете попробовать что-то вроде

s[4] = '0';

и посмотрите, будет ли "hello w0rld", когда вы звоните

puts(s);

Если это вызывает немедленную ошибку сегментации или исключение предотвращения выполнения данных, то, вероятно, оно доступно только для чтения. (Если система позволяет вам сойти с рук, это не делает ее хорошей идеей.)

...