|
|
  |
void const *argument, Что это? |
|
|
|
Jan 9 2014, 12:19
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(Herz @ Jan 9 2014, 10:11)  А каким образом это делается? Буквально в двух словах, если можно. На примере 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 */ Цитата(andrewlekar @ Jan 9 2014, 12:17)  На ARMах const в определении переменной заставляет компилятор (и линкер) размещать её во флэше. Компилятор - помещать ее в секцию данных "только для чтения". А линкер - размещать ее там, куда укажут в управляющем скрипте. Для прошиваемых намертво в небольшие процессоры программ эта секция обычно размещается во флеш. А вот если процессор побольше и программа загружается в огромное динамическое ОЗУ из какой-нибудь последовательной флешки - то и секцию констант программист скорее всего разместит в ОЗУ. Цитата(ViKo @ Jan 9 2014, 12:36)  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 к объявлению локальной переменной она перестает быть автоматической и может быть размещена во флеше, что вы и наблюдали. То есть никакой мистики тут нет и все происходит строго в рамках стандарта.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jan 9 2014, 18:55
|
Профессионал
    
Группа: Свой
Сообщений: 1 351
Регистрация: 21-05-10
Пользователь №: 57 439

|
Цитата(Сергей Борщ @ Jan 9 2014, 10:28)  Ну вот где вы такое видели применительно к языку 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 - Jan 9 2014, 19:19
|
|
|
|
|
Jan 10 2014, 08:04
|
Местный
  
Группа: Участник
Сообщений: 356
Регистрация: 9-06-07
Пользователь №: 28 315

|
Цитата то надо было указать квалификатор __flash. Об этом и речь квалификатор __flash - это расширение для данной архитектуры. Для стандарта языка квалификатор const - запрет на изменение переменной, не важно локальная она или глобальная. Размещенеие переменной в памяти - дело линкера. На тех же 51-х архитектурах обычный указатель содержит 3 байта - 2 адрес объекта (переменной) и один байт тип памяти, где этот объект распложен. А далее библиотека раскручивает цепочку и выбирает способ считывания данных. Но возможно и прямое указание типа памяти квалификаторами idata, xdata, code. (применительно к KEIL, у ИАР думаю похожая ситуация в отношении МCS-51). const только запрещает изменение перемнной не более того.
--------------------
Хорошую систему делают из стандартных блоков нестандартно мыслящие инженеры.
|
|
|
|
|
Jan 10 2014, 08:54
|
Профессионал
    
Группа: Свой
Сообщений: 1 975
Регистрация: 30-12-04
Из: Воронеж
Пользователь №: 1 757

|
Цитата(редактор @ Jan 10 2014, 12:04)  const только запрещает изменение перемнной не более того. Только в случае с указателем есть одна тонкость. Код const void *x; -- это указатель на константу. Вы не можете изменить то, на что он указывает, но можете изменить его самого: Код x = &y; Код void *const x; -- константный указатель. Вы не можете изменить этот указатель, но можете изменить то, на что он указывает: Код *x = y; Код const void *const x; -- константный указатель на константу. Вы не можете изменить ничего.
|
|
|
|
|
Jan 10 2014, 11:05
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(ViKo @ Jan 10 2014, 11:45)  Удостоверился в Кейл для глобальных переменных: Для процессора с линейным адресным пространством (ARM, Cortex). Для x51 все запутаннее - там есть и медленные generic указатели (с отметкой об адресном пространстве в старшем байте и с генерацией кодов доступа ко всем пространствам при обращении по такому указателю) и указатели на конретное адресное пространство (с квалификаторами data, idata, xdata и т.д). Тут подробнее. Насколько помню, по умолчанию (без спецификатора адресного пространства) константы располагаются в памяти data, т.е. в непосредственно адресуемом ОЗУ. С C166 не работал, не знаю, но судя по сегментированному адресному пространству тоже должны быть хитрости. Для других процессоров Keil вроде как компиляторов не делает.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jan 10 2014, 11:45
|
.
     
Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753

|
Цитата(ViKo @ Jan 7 2014, 14:50)  В C можно структуру передавать в функцию, именно, по значению, а не по ссылке. Т.е., имя структуры не есть ее адрес. В отличие от массива. Ну и как это связано с явным преобразованием идентификатора структуры? Разве при этом недостаточно информации о том, что "заказчик" желает взять именно её адрес? Более интересна ситуация, которую я нашёл у себя в исходниках, применения явного преобразования адреса к локальной (чаще регистровой) переменной. Вроде: Код void foo(float val) { u32 val32 = *(u32 *)&val;
u32 res32 = 0x80000000; if (val32 != 0) res32 = (((val32 & 0x007FFFFF) >> 1) | 0x00400000) | ...; .... } Вот здесь (во второй строке), спрашивается, компилятору хватит информации не облажаться.
Сообщение отредактировал GetSmart - Jan 10 2014, 13:27
--------------------
Заблуждаться - Ваше законное право :-)
|
|
|
|
|
Jan 10 2014, 11:59
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
Цитата(GetSmart @ Jan 10 2014, 14:45)  Ну и как это связано с явным преобразованием идентификатора структуры? Разве при этом недостаточно информации о том, что "заказчик" желает взять именно её адрес? Никак. С тем вопросом уже разобрались. Цитата Более интересна ситуация, которую я нашёл у себя в исходниках, применения явного преобразования адреса к локальной (чаще регистровой) переменной. Как это - адрес у регистровой переменной? Ну, для PIC-ов, где все переменные - регистры, можно понять. А вы о каком процессоре говорите?
|
|
|
|
|
Jan 10 2014, 12:07
|
.
     
Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753

|
Цитата(ViKo @ Jan 10 2014, 17:59)  Как это - адрес у регистровой переменной? Ну, для PIC-ов, где все переменные - регистры, можно понять. А вы о каком процессоре говорите? Там прикол в виртуальности этого адреса. По сути происходит/должно происходить интерпретация значения (битового представления) float как целочисленный u32. И это без использования временного union где-нибудь в оперативной памяти. Этот виртуальный адрес компилятор временно создаёт в своём личном формате хранения на этапе компиляции и только для себя, но передавать программе/программисту не обязан. А проблема заключается в явном преобразовании адреса с явным указанием (нового) адресного пространства. Цитата(ViKo @ Jan 10 2014, 17:59)  Никак. С тем вопросом уже разобрались. Обоснование Кейла не озвучено. Ещё интересно, как Кейл интерпретирует такое выражение: void *ptr; ptr = mb_cfg; // структура из начала темы Тоже, наверное, запретил. Хотя к массиву будет допустимо. Цитата(ViKo @ Jan 10 2014, 15:45)  Удостоверился в Кейл для глобальных переменных: - const (и static const, естественно) размещаются и используются из flash, - инициализированные переменные без квалификаторов (и volatile, естественно) при старте из flash переносятся в RAM и уже там используются. Кейлов много. Нужно указывать версию и для какого процессора. А при неуказании, сперва проверить на всех компиляторах Кейл для разных процессоров
Сообщение отредактировал GetSmart - Jan 10 2014, 14:51
--------------------
Заблуждаться - Ваше законное право :-)
|
|
|
|
|
Jan 10 2014, 14:13
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
Цитата(GetSmart @ Jan 10 2014, 15:07)  Ещё интересно, как Кейл интерпретирует такое выражение: void *ptr; ptr = mb_cfg; // структура из начала темы Тоже, наверное, запретил. Хотя к массиву будет допустимо. В середине темы по вашей просьбе я показал часть проекта с задачами - светодиодами, которая реально испытана на плате MCBSTM32 от Keil. Лично у меня нет никаких вопросов, которые стоило бы еще обсуждать в рамках заданной темы. upd. Нет, всплыл один вопросик. Выходит, константы лучше делать глобальными? Испортить их нельзя. А пригодиться они могут в разных функциях не раз. Цитата(GetSmart @ Jan 10 2014, 15:07)  Обоснование Кейла не озвучено. Cогласно языку C.
|
|
|
|
|
Jan 10 2014, 14:22
|
Профессионал
    
Группа: Свой
Сообщений: 1 351
Регистрация: 21-05-10
Пользователь №: 57 439

|
Цитата(andrewlekar @ Jan 10 2014, 08:29)  Что вы этим гениальным кодом хотите проверить? В ch сначала попадёт '5', затем в str1[0] запишется '5', затем в ch запишется '2', а строка ch=ch ничего не делает - она заоптимизируется почти всегда. Ах да, str1 и str2 будет размещено в ОЗУ. Если вы хотели str2 размещать во флэш, то надо было указать квалификатор __flash. Вы всегда отвечаете вопросом на вопрос? Может лучше посмотреть чем отгадывать? Цитата(ViKo @ Jan 10 2014, 12:45)  Удостоверился в Кейл для глобальных переменных: - const (и static const, естественно) размещаются и используются из flash, - инициализированные переменные без квалификаторов (и volatile, естественно) при старте из flash переносятся в RAM и уже там используются. Конкретно задавать нестандартные квалификаторы не вижу необходимости. О чем я и твержу.
|
|
|
|
|
Jan 10 2014, 17:30
|
Знающий
   
Группа: Участник
Сообщений: 837
Регистрация: 8-02-07
Пользователь №: 25 163

|
Цитата У кого есть IAR AVR? Цитата Для процессора с линейным адресным пространством (ARM, Cortex). Может уже хватит переливать из пустого в порожнее? То народ указатель на структуру от самой структуры отличить не может, то указатель на массив от самого массива, то общее адресное пространство от раздельного. Цитата Выходит, константы лучше делать глобальными? Испортить их нельзя. Если константа на самом деле где-то может пригодиться, то можете делать глобальной. Все подряд делать глобальными не стоит - экспортируется много символов и размываются интерфейсы у модулей.
|
|
|
|
|
  |
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0
|
|
|