Перейти к содержанию
    

А каким образом это делается? Буквально в двух словах, если можно.
На примере GCC: константы складываются в секции .rodata и .rodata.* Если вы в скрипте линкера разместите эти секции в flash (выходная секция .text), то они там и будут жить. А если вы поместите их в выходную секцию .data, то они будут размещены в ОЗУ и проинициализированы из флеша. Примерно так:

    .data :
    {
        . = ALIGN(4);
        _sdata = .;                /* start of .data label */
        *(.ramfunc)
        *(.ramfunc.*)
        *(.data)
        *(.data.*)
        *(.rodata)              /* read-only data (constants) */
        *(.rodata.*)
        . = ALIGN(4);
        _edata = .;                /* end of .data label */
    } > RAM AT > TEXT
    _sidata = LOADADDR(.data);    /* start of initialized data label */

 

На ARMах const в определении переменной заставляет компилятор (и линкер) размещать её во флэше.
Компилятор - помещать ее в секцию данных "только для чтения". А линкер - размещать ее там, куда укажут в управляющем скрипте. Для прошиваемых намертво в небольшие процессоры программ эта секция обычно размещается во флеш. А вот если процессор побольше и программа загружается в огромное динамическое ОЗУ из какой-нибудь последовательной флешки - то и секцию констант программист скорее всего разместит в ОЗУ.

 

static const

Строка просто const из flash переписывается в ОЗУ, и уже из ОЗУ используется в функции. Лично сталкивался.

Это какая-то чудовищная недоработка вашего компилятора. Допустим вы в файле myfile1.c размещаете глобальную переменную:

 char const Success_string[] = "Слава мне, победителю драконов";

Если вы объявите ее с квалификатором static, то ее область видимости будет ограничена только этим файлом и вы не сможете в файле myfile2.c написать

extern char const Success_string[];

void test()
{
    puts(Success_string);
}

А без static - сможете. И нет никаких объективных причин для компилятора размещать константу в одном случае в ОЗУ а в другом - во флеш.

 

....

 

Хотя... Я, кажется, понял в чем дело - вы имели дело с локальными переменными функции. В этом случае да, без static компилятор обязан создать переменную в точке объявления и уничтожить ее в конце области видимости. И сделать он это может только в ОЗУ. А с добавлением static к объявлению локальной переменной она перестает быть автоматической и может быть размещена во флеше, что вы и наблюдали. То есть никакой мистики тут нет и все происходит строго в рамках стандарта.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я, кажется, понял в чем дело - вы имели дело с локальными переменными функции.

Да, с локальными строками.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Да, с локальными строками.
О. А тут все о глобальных переменных спорили ;)

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ну вот где вы такое видели применительно к языку C в реальном мире?

 

На 51 уж 15 лет не писал, а на AVR и PIC реально размещал и утрамбовывал память.

 

К сожалению давно не программирую на этих процессорах. У кого есть IAR AVR?

Давайте простую программу напишем и создадим листинг ассемблерный. Тогда все станет ясно. Заодно map файл посмотрим.

Оптимизацию надо отключить

 

char str1[] = "12345";
const char str2[] = "54321";

char* ptr;
int main ()
{
       char ch;
       ptr = str2;
       ch = *ptr;
       ptr = str1;
       *ptr = ch;
       ptr++;
       ch = *ptr;
       ch=ch;
       return 0;
}

Изменено пользователем Tarbal

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Что вы этим гениальным кодом хотите проверить? В ch сначала попадёт '5', затем в str1[0] запишется '5', затем в ch запишется '2', а строка ch=ch ничего не делает - она заоптимизируется почти всегда. Ах да, str1 и str2 будет размещено в ОЗУ.

Если вы хотели str2 размещать во флэш, то надо было указать квалификатор __flash.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

то надо было указать квалификатор __flash.

Об этом и речь квалификатор __flash - это расширение для данной архитектуры.

Для стандарта языка квалификатор const - запрет на изменение переменной, не важно локальная она или глобальная. Размещенеие переменной в памяти - дело линкера.

На тех же 51-х архитектурах обычный указатель содержит 3 байта - 2 адрес объекта (переменной) и один байт тип памяти, где этот объект распложен. А далее библиотека раскручивает цепочку и выбирает способ считывания данных. Но возможно и прямое указание типа памяти квалификаторами idata, xdata, code. (применительно к KEIL, у ИАР думаю похожая ситуация в отношении МCS-51).

const только запрещает изменение перемнной не более того.

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

const только запрещает изменение перемнной не более того.
Только в случае с указателем есть одна тонкость.

const void *x;

-- это указатель на константу. Вы не можете изменить то, на что он указывает, но можете изменить его самого:

x = &y;

void *const x;

-- константный указатель. Вы не можете изменить этот указатель, но можете изменить то, на что он указывает:

*x = y;

const void *const x;

-- константный указатель на константу. Вы не можете изменить ничего.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Удостоверился в Кейл для глобальных переменных:

- const (и static const, естественно) размещаются и используются из flash,

- инициализированные переменные без квалификаторов (и volatile, естественно) при старте из flash переносятся в RAM и уже там используются.

Конкретно задавать нестандартные квалификаторы не вижу необходимости.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Удостоверился в Кейл для глобальных переменных:
Для процессора с линейным адресным пространством (ARM, Cortex).

 

Для x51 все запутаннее - там есть и медленные generic указатели (с отметкой об адресном пространстве в старшем байте и с генерацией кодов доступа ко всем пространствам при обращении по такому указателю) и указатели на конретное адресное пространство (с квалификаторами data, idata, xdata и т.д). Тут подробнее. Насколько помню, по умолчанию (без спецификатора адресного пространства) константы располагаются в памяти data, т.е. в непосредственно адресуемом ОЗУ.

С C166 не работал, не знаю, но судя по сегментированному адресному пространству тоже должны быть хитрости.

Для других процессоров Keil вроде как компиляторов не делает.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Ну и как это связано с явным преобразованием идентификатора структуры? Разве при этом недостаточно информации о том, что "заказчик" желает взять именно её адрес?

 

Более интересна ситуация, которую я нашёл у себя в исходниках, применения явного преобразования адреса к локальной (чаще регистровой) переменной. Вроде:

void foo(float val)
{
    u32 val32 = *(u32 *)&val;

    u32 res32 = 0x80000000;
    if (val32 != 0)
        res32 = (((val32 & 0x007FFFFF) >> 1) | 0x00400000) |
                ...;
....
}

Вот здесь (во второй строке), спрашивается, компилятору хватит информации не облажаться.

Изменено пользователем GetSmart

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ну и как это связано с явным преобразованием идентификатора структуры? Разве при этом недостаточно информации о том, что "заказчик" желает взять именно её адрес?

Никак. С тем вопросом уже разобрались.

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

Как это - адрес у регистровой переменной? Ну, для PIC-ов, где все переменные - регистры, можно понять. А вы о каком процессоре говорите?

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Как это - адрес у регистровой переменной? Ну, для PIC-ов, где все переменные - регистры, можно понять. А вы о каком процессоре говорите?

Там прикол в виртуальности этого адреса. По сути происходит/должно происходить интерпретация значения (битового представления) float как целочисленный u32. И это без использования временного union где-нибудь в оперативной памяти. Этот виртуальный адрес компилятор временно создаёт в своём личном формате хранения на этапе компиляции и только для себя, но передавать программе/программисту не обязан. А проблема заключается в явном преобразовании адреса с явным указанием (нового) адресного пространства.

 

Никак. С тем вопросом уже разобрались.

Обоснование Кейла не озвучено.

Ещё интересно, как Кейл интерпретирует такое выражение:

void *ptr;

ptr = mb_cfg; // структура из начала темы

Тоже, наверное, запретил. Хотя к массиву будет допустимо.

 

Удостоверился в Кейл для глобальных переменных:

- const (и static const, естественно) размещаются и используются из flash,

- инициализированные переменные без квалификаторов (и volatile, естественно) при старте из flash переносятся в RAM и уже там используются.

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

Изменено пользователем GetSmart

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ещё интересно, как Кейл интерпретирует такое выражение:

void *ptr;

ptr = mb_cfg; // структура из начала темы

Тоже, наверное, запретил. Хотя к массиву будет допустимо.

В середине темы по вашей просьбе я показал часть проекта с задачами - светодиодами, которая реально испытана на плате MCBSTM32 от Keil. Лично у меня нет никаких вопросов, которые стоило бы еще обсуждать в рамках заданной темы.

 

upd. Нет, всплыл один вопросик. Выходит, константы лучше делать глобальными? Испортить их нельзя. А пригодиться они могут в разных функциях не раз.

 

Обоснование Кейла не озвучено.

Cогласно языку C.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Что вы этим гениальным кодом хотите проверить? В ch сначала попадёт '5', затем в str1[0] запишется '5', затем в ch запишется '2', а строка ch=ch ничего не делает - она заоптимизируется почти всегда. Ах да, str1 и str2 будет размещено в ОЗУ.

Если вы хотели str2 размещать во флэш, то надо было указать квалификатор __flash.

 

Вы всегда отвечаете вопросом на вопрос?

Может лучше посмотреть чем отгадывать?

 

Удостоверился в Кейл для глобальных переменных:

- const (и static const, естественно) размещаются и используются из flash,

- инициализированные переменные без квалификаторов (и volatile, естественно) при старте из flash переносятся в RAM и уже там используются.

Конкретно задавать нестандартные квалификаторы не вижу необходимости.

 

О чем я и твержу.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

У кого есть IAR AVR?

Для процессора с линейным адресным пространством (ARM, Cortex).

 

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

 

Выходит, константы лучше делать глобальными? Испортить их нельзя.

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...