Как сохранить переменную в определенном месте памяти?

c

28957 просмотра

7 ответа

Поскольку я относительно новичок в C, я должен использовать для одного из моих проектов следующее: я должен объявить некоторые глобальные переменные, которые должны храниться каждый раз, когда программа запускается по тому же адресу памяти. Я прочитал и обнаружил, что я объявляю его «статическим», он будет храниться в той же ячейке памяти.

Но мой вопрос: могу ли я указать программе, где хранить эту переменную или нет. Например: int a будет храниться в 0xff520000. Можно ли это сделать или нет? Я искал здесь, но не нашел соответствующего примера. Если это какой-то старый пост по этому поводу, пожалуйста, поделитесь ссылкой.

Спасибо всем заранее. Лауренцию

Обновление: я использую 32uC

Автор: Laurentiu Источник Размещён: 12.11.2019 09:06

Ответы (7)


10 плюса

Решение

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

Далее, обратите внимание, что не имеет смысла отображать переменные по определенным адресам, если они не являются аппаратными регистрами или энергонезависимыми переменными, находящимися во флэш-памяти или EEPROM.

Если содержимое такой ячейки памяти изменится во время выполнения, потому что это регистр, или потому что ваша программа содержит загрузочный алгоритм / алгоритм программирования NVM, изменяющий ячейки памяти NVM, то переменные должны быть объявлены как volatile. В противном случае компилятор полностью сломает ваш код при оптимизации.

Конкретный компилятор, скорее всего, имеет нестандартный способ размещения переменных по определенным адресам, такой как #pragma или иногда странный, нестандартный @оператор. Единственный разумный способ, которым вы можете разместить переменную в фиксированном месте в стандарте C, это:

#define MY_REGISTER (*(volatile uint8_t*)0x12345678u)

где 0x12345678 - адрес, где находится 1 байт. Когда у вас есть такое объявление макроса, вы можете использовать его, как если бы оно было переменной:

void func (void)
{
  MY_REGISTER = 1;  // write
  int var = MY_REGISTER;  // read
}

Чаще всего вы хотите, чтобы переменные такого рода находились в глобальном пространстве имен, а следовательно, и в макросе. Но если по какой-то причине вы хотите уменьшить область действия переменной, пропустите макрос и получите доступ к адресу вручную внутри кода:

void func (void)
{
  *(volatile uint8_t*)0x12345678u = 1; // write
  int var = *(volatile uint8_t*)0x12345678u; // read
}
Автор: Lundin Размещён: 07.03.2013 10:32

8 плюса

Вы можете сделать это с помощью скриптов компоновщика, что довольно часто встречается во встроенном программировании.

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

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

Автор: Ben Jackson Размещён: 07.03.2013 09:11

1 плюс

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

Автор: Tony The Lion Размещён: 07.03.2013 09:10

1 плюс

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

int addr = 0xff520000;

int main()
{
    *((int*)addr) = 42;
    ...
    return 0;
}

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

Автор: SomeWittyUsername Размещён: 07.03.2013 09:16

0 плюса

Не на уровне C. Если вы работаете с языком ассемблера, вы можете напрямую управлять макетом памяти. Но компилятор C делает это за вас. Вы не можете действительно возиться с этим.

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

Автор: luser droog Размещён: 07.03.2013 09:10

0 плюса

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

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

Автор: Art Размещён: 07.03.2013 09:14

0 плюса

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

int* myIntPointer = 0xff520000;
Автор: SteveP Размещён: 07.03.2013 09:16
Вопросы из категории :
32x32