Как память, доступная только для чтения, реализована в C?

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

char *s = "hello world". 

«мир привет» фактически хранится в памяти только для чтения.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

 s[4] = '0'; 

и посмотрите, не говорит ли он «привет w0rld», когда вы звоните

 puts(s); 

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

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

Но когда вы пишете char *s="sneha"; вы не выделяете место для хранения "sneha" . Он будет храниться в разделе READ ONLY. Но указатель 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