Портативные адреса памяти в C? - PullRequest
0 голосов
/ 20 января 2020

Скажем, у нас есть программа 1 ...

. / Program1

int main(int argc, char *argv[])
{
  int *i;
  *i = 10;
  printf("%lld", i);
  return 0;
}

Теперь программа 2 ...

. / Program2 program1output 10

int main(int argc, char *argv[])
{
  int *t;
  t = (int*)atoll(argv[1]);
  *t = atoi(argv[2]);
  return 0;
}

Будет ли это работать? Можно ли разделять адреса памяти между разными программами?

Ответы [ 3 ]

3 голосов
/ 20 января 2020

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

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

В специальной операционной системе разные процессы могут совместно использовать одно адресное пространство.

Дополнение

Это неправильный код:

int *i;
*i = 10;

Объявление int *i; определяет i как указатель, но не присваивает ему значение. Тогда использование *i нецелесообразно, поскольку оно пытается сослаться на то, куда указывает i, но i не было назначено указывать на что-либо.

Чтобы определить int и сделать его адрес видимым в вы можете определить int i; и затем напечатать &i.

. Это неправильный способ печати адреса:

printf("%lld", i);

Чтобы напечатать адрес, приведите его к void * и отформатируйте его %p. Результат форматирования определяется реализацией:

printf("%p", (void *) &i);

Это неправильный способ восстановления адреса:

int *t;
t = (int*)atoll(argv[1]);

Как и в случае printf, тип должен быть void *, и возникают проблемы при попытке преобразования с atoll. Стандарт C не гарантирует, что он будет работать; формат, полученный при печати с %p, может не быть обычным целочисленным форматом. Вместо этого используйте спецификатор %p с sscanf:

void *temp;
if (1 != sscanf(argv[1], "%p", &temp))
    exit(EXIT_FAILURE);
int *t = temp;

Когда адрес исходит из другого процесса, поведение преобразования sscanf не определяется стандартом C.

0 голосов
/ 20 января 2020

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

(Не во всех средах есть виртуальная память. Например, встроенная система может этого не делать.)

Если в одном процессе выполняются две программы, между ними можно передать указатель. Например, основная программа может передать указатель на динамически связанную библиотеку, которую она загружает.


0 голосов
/ 20 января 2020

В принципе, приложение работает с собственной / частной памятью. Существуют способы разделения памяти между различными процессами, но для этого требуется специальный механизм для преодоления вышеупомянутого «принципала» (например, файлы, отображаемые в память). Кратко рассмотрим, например, эту статью о совместном использовании памяти.

В вашем случае программа 1 закончилась, а ее память больше не доступна; и способ доступа к нему определенно не является одним из «специальных механизмов», необходимых для доступа к разделяемой памяти:

Хотя целочисленная переменная может быть преобразована в значение указателя, доступ к этому указателю действителен, только если целочисленное значение Первоначально был преобразован из указателя на действительный объект. Это не так в вашем примере, так как интегральное значение, вычисленное в t = (int*)atoll(argv[1]);, никогда не указывало на действительный объект в текущей программе.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...