Можем ли мы присвоить значение определенной ячейке памяти? - PullRequest
10 голосов
/ 21 февраля 2012

Я хочу присвоить какое-то значение (скажем, 2345) ячейке памяти (скажем, 0X12AED567).Можно ли это сделать?

Другими словами, как я могу реализовать следующую функцию?

void AssignValToPointer(uint32_t pointer, int value)
{

}

Ответы [ 7 ]

16 голосов
/ 21 февраля 2012

Тот факт, что вы задаете этот вопрос, указывает на то, что вы над головой.Но здесь вы идете:

*(int *)0x12AED567 = 2345;
3 голосов
/ 21 февраля 2012

Ответ зависит от некоторых факторов. Ваша программа работает в современной операционной системе?

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

2 голосов
/ 21 февраля 2012

Что касается C, это неопределенное поведение. Мое следующее предложение также является неопределенным поведением, но позволяет избежать всех проблем, связанных с типами и псевдонимами: Используйте символы.

int a = get_value();
char const * const p = (const char * const)&a;
char * q = (char *)0x12345;

memcpy(q, p, sizeof(int));

Кроме того, вы можете получить доступ к байтам q[i] напрямую. (Это часть, которая является UB: указатель q не был получен как адрес фактического объекта или как результат функции выделения. Иногда это нормально; например, если вы пишете автономно Программа, которая работает в реальном режиме и обращается к графическому оборудованию, вы можете записывать в графическую память напрямую по общеизвестному жестко закодированному адресу.)

2 голосов
/ 21 февраля 2012

Просто обработайте область памяти как указатель

int* pMemory =  OX12AED567;
*pMemory = 2345;

Примечание. Это будет работать, только если эта область памяти доступна и доступна для записи вашей программой.Запись в произвольную область памяти, подобную этой, по своей природе опасна.

1 голос

Стандартный черновик C99

Это, вероятно, невозможно без поведения, определенного реализацией.

О таких приведениях, как:

*(uint32_t *)0x12AED567 = 2345;

the C99 N1256 стандартный черновик «6.3.2.3 Указатели» гласит:

5 Целое число может быть преобразовано в любой тип указателя.За исключением случаев, указанных ранее, результат определяется реализацией, может быть неправильно выровнен, может не указывать на объект ссылочного типа и может быть представлением прерывания.56)

Реализация GCC

GCC документирует свою реализацию int для указателя по адресу: https://gcc.gnu.org/onlinedocs/gcc-5.4.0/gcc/Arrays-and-pointers-implementation.html#Arrays-and-pointers-implementation

Приведение из целого числаto pointer отбрасывает наиболее значимые биты, если представление указателя меньше целочисленного типа, расширяется в соответствии со знаком целочисленного типа, если представление указателя больше целочисленного типа, в противном случае биты не изменяются.

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

1 голос
/ 21 февраля 2012

Вы указали, что адрес является физическим адресом, и ваш код выполняется в процессе.

Так что, если вы

  1. вЭто операционная система высокого уровня, например, Linux, вам нужно сопоставить физическое адресное пространство.В Linux / dev / mem делает это за вас.

  2. в ядре или без операционной системы и с MMU, вы должны преобразовать физический адрес в виртуальный адрес.В ядре Linux, Phys_to_virt () делает это за вас.В ядре, я полагаю, этот адрес всегда отображается.

  3. в ядре или без операционной системы и без MMU вы пишете непосредственно по этому адресу.Совсем нет необходимости в сопоставлении.

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

void AssignValToPointer(uint32_t pointer, int value)
{
    * ((volatile int *) pointer) = value;
}

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

Вы можететакже нужно использовать тип данных uintptr_t вместо uint32_t для указателя.

0 голосов
/ 21 февраля 2012

С условием, что это не портативно или безопасно (вообще):

*((int *)0x12AED567) = 2345;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...