Софтуерно Инженерство
Loading...
+ Нов въпрос
denka avatar denka 52 Точки

Начини за писане в паметта, която е само за четене

Здравейте,

Гледам лекциите от курса по С с идеята да се подготвя за новия курс "Програмиране под линукс". Стигнах до указателите и работата с памет и стигнах до въпроса "Кога декларирайки променливи в една функция тяхната памет се заделя в стека и кога тяхната памет се заделя в read only областта?".

Например, ако декларирам 

char str[] = "abcd"; - Стринга "abcd"  се заделя в стека и в момента в който изляза от функцията тази памет ще се зачисти.

char * str = "abcd" - Тук стринга "abcd" вече се заделя в read only паметта и си стои там дори и след като изляза от функцията в която съм я декларирала.

Та това ме кара да се замисля какви са другите начини за писане в read only паметта? Мога ли да пазя там нещо друго освен стрингове? Примерно масив от int или само int?

Знам, че ако искам да имам контрол над паметта мога да ползвам heap, но тук не целя да направя нищо конкретно, просто искам да разбера как работи.

 

Тагове:
0
C Programming
marks avatar marks 23 Точки
Best Answer

За да пишеш в read only паметта по време на изпълнение на програмата, ще трябва да модифицираш memory access permissions при самото изпълнение на програмата.

#include <sys/mman.h>

void *addr  = get_address_of_instruction_pointer();
int  length = 4096;   /* size of a page */

if (mprotect(addr, length, PROT_READ | PROT_WRITE) == 0) {
    /* current code page is now writable */
}

 

Ако искаш да запишеш някакви данни различни от string в read only паметта по време на компилацията и линкването, ще трябва да си измислиш схема по която да ги прекодираш в string и да си напишеш съответните функции за преобразуване. Base64 може да ти е от полза.

2
fristgerb avatar fristgerb 50 Точки

Здрасти! :)

По-лесно е да се отговори на такива въпроси, когато има цел която искаш да постигнеш. :)

Когато имаш низ-литерал "abcd", този низ се записва от операционната система в паметта още преди стартирането на програмата. Паметта в която е "abcd" е read-only, в мисъл, че програмния код не може да променя или заделя такава памет.

При израза char *str = "abcd" програмата прави стойност, която е адресът (pointer) на низа "abcd" в read-only паметта. Ако имаш множество еднакви низове на различни места в source кода, то в read-only паметта има само един низ към който всички променливи сочат.

+----------------+
|stack:          |
|  char *str  >--+-----+
|  char *str2 >--+---+ |
|                |   | |
+----------------+   | |
|heap:           |   | |
|                |   | |
+----------------+   | |
|read-only:      |   | |
|  "abcd" <------+---+-+
|                |
+----------------+

Няма сходен синтаксис за други видове стойности, масиви от друг тип или самостоятелен int, но сигурно има други начини да постигнеш същия резултат, зависимост какво точно искаш да направиш.

Това отговаря ли ти на въпроса? :)

1
denka avatar denka 52 Точки

Здравей :)

Не ми отговаря на въпроса :) Аз изхождам от това какви са ми възможните опции, иначе (поне за сега) не се сещам за нещо, което да не мога да направя през хиипа. Та паметта, която мога да ползвам е:

1. стек - тук е ясно как да си дефинирам променлива от какъвто и да е тип, ясно е, че се чисти автоматично след излизане от функцията и е хубаво да се ползва за малки по обем данни.

2. хиипа - пак е ясно как да си дефинирам каквото и да е, трябва да се грижа за освобождаването на паметта там, ползва се за големи по - обем данни.

3. паметта за четене - до тук ми е ясно само как да си дефинирам стринг там. Удобна е за константи. Принципно всичко дефинирано тук мога със същия успех да го дефинирам и в хиипа, но доста по - логично е за малки по обем данни, които се ползват често да се ползва тази памет. И не виждам причина да не мога да сложа вътре примерно double pi = 3.14.... В общи линиии може да се ползва в случаите, когато би се ползвал стека, но данните трябват и след приключване на функцията.

4. паметта за неинициализирани глобални променливи - нея не съм я разглеждала подробно още

Та горе долу долу това е. Как се ползват различните видове памет и кои са добрите практики за всяка от тях.

0
fristgerb avatar fristgerb 50 Точки

Аз бих ги разделил видовете памет на 4 основни вида:

  • Stack
  • Heap
  • Static
  • Read-only

Други по-добре биха казали какви са „добрите практики“, но аз не съм привърженик на подобни решения. Аз смятам, че знаейки какви видове памет и какъв синтаксис има, най-добре е да осмислиш в конкретния случай какви са предимствата и недостатъците, ако нещо може да бъде направено по няколко различни начина.

Удобна е за константи. Принципно всичко дефинирано тук мога със същия успех да го дефинирам и в хиипа, но доста по - логично е за малки по обем данни, които се ползват често да се ползва тази памет. И не виждам причина да не мога да сложа вътре примерно double pi = 3.14

Аз не виждам логиката, която ти виждаш. :)

Защо смяташ, че е логично често използвани малки данни да са точно в тази памет? Константи като числото pi типично се дефинират като глобални променливи или като #define макрота.

При кодът char *str = "abcd" низът е зададен като литерал, не чрез константа. Литералите и константите просто са различни неща, ползвани по различен начин, затова и не виждам логика в примера, който даваш.

-1
02/01/2016 04:52:49
itonev avatar itonev 22 Точки

Напрактика може малко да опростим нещата и да кажем така.

Всичко е Heap. :)

За всичко смислено, сериозно се ползва хйипа.

То и в другите езици е така. 

Когато пишеш :

Object o = new Object()

Това си му викат референция ни си е чист управляем пойнтър към хийп.

И в C имаме както следва:

Искаш константа ? Правиш я макрос.

Локални променливи и масиви за функция са си на стека 

Връщаш указател от функция, на хийпа :)

 

 

 

-1