|
void const *argument, Что это? |
|
|
|
 |
Ответов
(1 - 62)
|
Jan 6 2014, 20:18
|

Профессионал
    
Группа: Свой
Сообщений: 1 080
Регистрация: 16-11-04
Из: СПб
Пользователь №: 1 143

|
если оно будет на стеке, то по моменту запуска самой задачи естветсвено всё уплывет.
то есть так нельзя Suart_init mb_cfg = { 0, 9600 }; task_start( mb_task, ..., (void*)mb_cfg );
а так можно const Suart_init mb_cfg = { 0, 9600 }; task_start( mb_task, ..., (void*)mb_cfg );
или так static Suart_init mb_cfg = { 0, 9600 }; task_start( mb_task, ..., (void*)mb_cfg );
--------------------
Марс - единственная планета, полностью населенная роботами (около 7 штук).
|
|
|
|
|
Jan 6 2014, 20:35
|

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

|
Цитата(megajohn @ Jan 6 2014, 22:57)  то есть как реально в RTX синтаксис вызова не в курсе, но суть передал - вызов задач с конкретными параметрами. Спасибо! Понял. Проверил в действии. Работает. Нужно поправить - брать адрес структуры. Код task_start( mb_task, ..., (void*)&mb_cfg );
|
|
|
|
|
Jan 6 2014, 23:38
|
.
     
Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753

|
Вообще-то компилятор должен "съедать" этот параметр при вызове функции и без явного преобразования. Как и для параметра "void *" компилятор должен принимать указатель на любой неконстантный объект из соответствующего адресного пространства. Если отказывается, то это наверное плохой компилятор. Без явного преобразования очевидно, что безопаснее. Цитата(ViKo @ Jan 7 2014, 02:35)  Нужно поправить - брать адрес структуры. Какая разница в данном случае, с амперсандом или без? В случае когда голый идентификатор структуры без указания поля. Однозначнее, конечно, было бы с амперсандом, но на данный момент в Си оба варианта вроде бы одинаковые. Цитата(megajohn @ Jan 7 2014, 02:18)  если оно будет на стеке, то по моменту запуска самой задачи естветсвено всё уплывет. Квалификатор const не запретит передачу локальной переменной. Не встать на грабли - забота программиста. const в параметре "проявит себя" только внутри тела функции, когда этот указатель без явного преобразования будет передан параметром или присвоен другому типизированному указателю на константу. Цитата(megajohn @ Jan 7 2014, 02:18)  то есть так нельзя Suart_init mb_cfg = { 0, 9600 }; task_start( mb_task, ..., (void*)mb_cfg );
а так можно const Suart_init mb_cfg = { 0, 9600 }; task_start( mb_task, ..., (void*)mb_cfg ); Второй вариант тоже будет на стеке. Просто менять его значения нельзя будет.
Сообщение отредактировал GetSmart - Jan 7 2014, 02:22
--------------------
Заблуждаться - Ваше законное право :-)
|
|
|
|
|
Jan 7 2014, 08:50
|

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

|
Цитата(GetSmart @ Jan 7 2014, 02:38)  Какая разница в данном случае, с амперсандом или без? В случае когда голый идентификатор структуры без указания поля. Однозначнее, конечно, было бы с амперсандом, но на данный момент в Си оба варианта вроде бы одинаковые. Возможно, в других языках варианты одинаковые. Но не в С. В C можно структуру передавать в функцию, именно, по значению, а не по ссылке. Т.е., имя структуры не есть ее адрес. В отличие от массива.
|
|
|
|
|
Jan 7 2014, 10:08
|
.
     
Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753

|
Цитата(ViKo @ Jan 7 2014, 14:50)  Возможно, в других языках варианты одинаковые. Но не в С. Чем отличается результат двух вариантов выражений со структурами ниже? Код (void*)&mb_cfg и (void*)mb_cfg Если отличаются, то в каких компиляторах. Идентификатор/имя массива тоже не является адресом его первого элемента. Иначе выражение &mass было бы аналогом &(&mass[0]). Взятие адреса от адреса в Си допустимо?
Сообщение отредактировал GetSmart - Jan 7 2014, 10:18
--------------------
Заблуждаться - Ваше законное право :-)
|
|
|
|
|
Jan 7 2014, 10:18
|

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

|
Цитата(GetSmart @ Jan 7 2014, 13:08)  Чем отличается результат двух вариантов выражений со структурами ниже? Код (void*)&mb_cfg и (void*)mb_cfg Если отличаются, то в каких компиляторах. Тем, что второй вариант не компилируется. Keil V5.1.0 source\exsUSB.c(164): error: #171: invalid type conversion Led9_id = osThreadCreate(osThread(Led_thread), (void *)led9); А в каком компиляторе работают оба?
|
|
|
|
|
Jan 7 2014, 10:20
|

Профессионал
    
Группа: Свой
Сообщений: 1 080
Регистрация: 16-11-04
Из: СПб
Пользователь №: 1 143

|
Цитата(GetSmart @ Jan 7 2014, 03:38)  Квалификатор const не запретит передачу локальной переменной. Не встать на грабли - забота программиста. const в параметре "проявит себя" только внутри тела функции, когда этот указатель без явного преобразования будет передан параметром или присвоен другому типизированному указателю на константу. не знаю как в высших материях, но в дизамсе передается просто адрес. Задача компилятора - ругатся при попытке записи по const* Цитата(GetSmart @ Jan 7 2014, 03:38)  Второй вариант тоже будет на стеке. Просто менять его значения нельзя будет. если это AVR то будет во флеше, если ARM то как указано в линкере ROM_region. А в других архитектурах как решит компиляторы, но размещать const на стеке вызывающей задачи - сомнительно. Цитата(ViKo @ Jan 7 2014, 00:35)  Нужно поправить - брать адрес структуры. Код task_start( mb_task, ..., (void*)&mb_cfg ); да, мой косяк. Вместо компилятора под руками была текила, и это зло вчера меня победило
--------------------
Марс - единственная планета, полностью населенная роботами (около 7 штук).
|
|
|
|
|
Jan 7 2014, 10:38
|
.
     
Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753

|
Цитата(ViKo @ Jan 7 2014, 16:18)  Led9_id = osThreadCreate(osThread(Led_thread), (void *)led9); А в каком компиляторе работают оба?  Предъявите объявление led9. Проверьте для корректности все предыдущие версии Кейла. Если раньше оба варианта допускались, то как разработчики это обосновали и обосновали ли? Цитата(megajohn @ Jan 7 2014, 16:20)  если это AVR то будет во флеше, То есть от компилятора не зависит? Цитата(megajohn @ Jan 7 2014, 16:20)  не знаю как в высших материях, но в дизамсе передается просто адрес. Задача компилятора - ругатся при попытке записи по const* Я имел ввиду "проявит себя" на этапе компиляции. По сути то же самое. Вне тела функции наличие квалификатора const никак не ограничивает передачу параметров по сравнению с вариантом без квалификатора const (в прототипе функции).
Сообщение отредактировал GetSmart - Jan 7 2014, 10:50
--------------------
Заблуждаться - Ваше законное право :-)
|
|
|
|
|
Jan 7 2014, 10:42
|

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

|
Цитата(GetSmart @ Jan 7 2014, 13:29)  Предъявите объявление led9. CODE typedef struct { uint16_t leds; uint32_t dels; } thread_init;
const thread_init led8 = {0x0100, 500}; const thread_init led9 = {0x0200, 498}; const thread_init led10 = {0x0400, 496}; const thread_init led11 = {0x0800, 494}; const thread_init led12 = {0x1000, 492}; const thread_init led13 = {0x2000, 490}; const thread_init led14 = {0x4000, 488}; const thread_init led15 = {0x8000, 486};
void Led_thread(void const *arg); // прототип
osThreadId Led8_id; osThreadId Led9_id; osThreadId Led10_id; osThreadId Led11_id; osThreadId Led12_id; osThreadId Led13_id; osThreadId Led14_id; osThreadId Led15_id;
osThreadDef(Led_thread, osPriorityNormal, 1, 0);
int32_t main(void) { ... Led8_id = osThreadCreate(osThread(Led_thread), (void *)&led8); Led9_id = osThreadCreate(osThread(Led_thread), (void *)&led9); Led10_id = osThreadCreate(osThread(Led_thread), (void *)&led10); Led11_id = osThreadCreate(osThread(Led_thread), (void *)&led11); Led12_id = osThreadCreate(osThread(Led_thread), (void *)&led12); Led13_id = osThreadCreate(osThread(Led_thread), (void *)&led13); Led14_id = osThreadCreate(osThread(Led_thread), (void *)&led14); Led15_id = osThreadCreate(osThread(Led_thread), (void *)&led15); ... }
void Led_thread(void const *arg) { while (true) { GPIOB->BSRR = ((thread_init *)arg)->leds; osDelay(((thread_init *)arg)->dels); GPIOB->BSRR = ((thread_init *)arg)->leds << 16; osDelay(((thread_init *)arg)->dels); } }
|
|
|
|
|
Jan 8 2014, 11:10
|

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

|
Цитата(GetSmart @ Jan 8 2014, 13:56)  Кейлу логично было бы запретить использование (void *)&mass. Наверное, так оно и есть. Проверил. Получил. uint16_t arr[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; uint16_t *parr = &arr; source\Exercises.c(159): error: #144: a value of type "uint16_t (*)[10]" cannot be used to initialize an entity of type "uint16_t *" На uint16_t *parr = &arr[0]; не ругается, естественно. На uint16_t *parr = (uint16_t *)&arr; тоже не ругается!
|
|
|
|
|
Jan 9 2014, 01:29
|

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

|
Цитата(ViKo @ Jan 8 2014, 20:30)  Почему же он неявное приведение не делает? Потому что таковы правила языка. Это называется "безопасность типов" (type safety). Он не даем вам случайно спутать теплое с мягким и мух с котлетами. Но и оставляет вам право сделать это, если вам это действительно нужно, через явное приведение типов.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jan 9 2014, 07:28
|

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

|
Цитата(Tarbal @ Jan 9 2014, 04:47)  В процессорах с Гарвардской архитектурой AVR, PIC, 8051 константы размещаются во флеше. Ну вот где вы такое видели применительно к языку C в реальном мире? Квалификатор const лишь дает гарантию, что компилятор не допустит изменения переменной с таким квалификатором. И никоим образом не влияет на адресное пространство. Если вы объявили переменную с квалификатором const - под нее точно так же будет выделено место в ОЗУ. вот вам простой пример: Код char string1[] = " string1"; char const string2[] = "string2";
void print_string(char const * string) // const тут гарантирует, что функция не изменит переданную ей строку { .........
string[0] = '+'; // компилятор даст по рукам. В объявлении параметра мы обещали, что не будем его менять }
void empty_string(char * string) // а вот тут гарантий нет, переданная строка может быть изменена. { ......... string[1] = '+'; // пожалуйста }
void test() { print_string(string1); // да без проблем, в соответствии с правилами языка print_string(string2); // тоже запросто
empty_string(string1); // легко empty_string(string2); // нифига. const в объявлении string2 запрещает, функция может модифицировать строку
string1[0] = "!"; // да, пожалуйста string2[0] = "x"; // а вот фиг } А теперь объясните, каким образом print_string() будет понимать - ей передали указатель на строку во флеше или на строку в ОЗУ? Именно поэтому каждый компилятор добавляет расширения - вводит дополнительные квалификаторы для указания адресного пространства. Цитата(Tarbal @ Jan 9 2014, 04:47)  Передавая такой параметр в функцию надо дать знать в каком пространстве памяти находится параметр, чтобы функция использовала правильные ассемблерные команды. Для этого и используется слово const. Pic использует слово flash кажется, но это в микрочиповском компиляторе. Нет. слово const используется для другого. Как раз слово flash явлается расширением языка - квалификатором адресного пространства и используется именно для этого. А вот в процессорах с единым адресным пространством (ARM, x86, MSP430) досуп к переменным во флеше или в ОЗУ на чтение одинаков, поэтому именно в них возможно указать линкеру размещать константные переменные во флеше не загружая копию в ОЗУ. А можно указать хранить в ОЗУ и все будет как у больших машин.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jan 9 2014, 08:16
|

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

|
Цитата(Сергей Борщ @ Jan 9 2014, 10:28)  А вот в процессорах с единым адресным пространством (ARM, x86, MSP430) досуп к переменным во флеше или в ОЗУ на чтение одинаков, поэтому именно в них возможно указать линкеру размещать константные переменные во флеше не загружая копию в ОЗУ. А можно указать хранить в ОЗУ и все будет как у больших машин. Есть способ - указать квалификатор static. Код static const uint8_t *SourTxt[] = {"Кан1", "Кан2"}; В ОЗУ этих строк не будет. Сразу будут читаться из флэш программы.
|
|
|
|
|
Jan 9 2014, 10:20
|
Гуру
     
Группа: Свой
Сообщений: 3 123
Регистрация: 7-04-07
Из: Химки
Пользователь №: 26 847

|
Использование ключевых слов static и/или const для управления размещением данных (будь то flash или еще что) - вещь на 100% зависящая от конкретного компилятора. Стандарт С/С++ вообще не знает о том, что такое flash и как в нее помещать данные  Поэтом, прежде чем советовать что то типа Цитата Есть способ - указать квалификатор static. В ОЗУ этих строк не будет. Сразу будут читаться из флэш программы. стоит указать, для каких именно компиляторов это справедливо
|
|
|
|
|
Jan 9 2014, 10:27
|
Знающий
   
Группа: Участник
Сообщений: 837
Регистрация: 8-02-07
Пользователь №: 25 163

|
Цитата для каких именно компиляторов Ни для каких. static очевидно может изменяться во время выполнения программы и не может быть размещён во flash. const размещает переменные во flash независимо от квалификатора static - актуально для IAR для ARM.
|
|
|
|
|
Jan 9 2014, 10:36
|

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

|
Цитата(XVR @ Jan 9 2014, 13:20)  Поэтом, прежде чем советовать что то типа стоит указать, для каких именно компиляторов это справедливо Для компилятора, входящего в состав Keil uVision. Пользуюсь этими квалификаторами. О каком компиляторе идет речь, видно в теме неоднократно. Цитата(andrewlekar @ Jan 9 2014, 13:27)  static очевидно может изменяться во время выполнения программы и не может быть размещён во flash. const размещает переменные во flash независимо от квалификатора static - актуально для IAR для ARM. static constСтрока просто const из flash переписывается в ОЗУ, и уже из ОЗУ используется в функции. Лично сталкивался. И получал на форуме совет. И от кого, помню.
|
|
|
|
|
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). Может уже хватит переливать из пустого в порожнее? То народ указатель на структуру от самой структуры отличить не может, то указатель на массив от самого массива, то общее адресное пространство от раздельного. Цитата Выходит, константы лучше делать глобальными? Испортить их нельзя. Если константа на самом деле где-то может пригодиться, то можете делать глобальной. Все подряд делать глобальными не стоит - экспортируется много символов и размываются интерфейсы у модулей.
|
|
|
|
|
Jan 10 2014, 19:22
|
.
     
Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753

|
Цитата(Tarbal @ Jan 9 2014, 08:47)  В процессорах с Гарвардской архитектурой AVR, PIC, 8051 константы размещаются во флеше. ... Для этого и используется слово const. Pic использует слово flash кажется, но это в микрочиповском компиляторе. С другими не работал не знаю. Стандартный прототип memcpy: void *memcpy(void *s1, const void *s2, size_t n); копирует из ОЗУ в ОЗУ. Цитата(Tarbal @ Jan 10 2014, 00:55)  К сожалению давно не программирую на этих процессорах. У кого есть IAR AVR? IAR AVR именно так и интерпретирует const. Как не меняющий адресное пространство.
--------------------
Заблуждаться - Ваше законное право :-)
|
|
|
|
|
Jan 11 2014, 06:32
|
Знающий
   
Группа: Участник
Сообщений: 837
Регистрация: 8-02-07
Пользователь №: 25 163

|
Цитата Ничего не понял. Может попробуете еще раз выразить свою мысль? В вашем коде для AVR все переменные будут размещены в ОЗУ. Хотите их размещать во флэш - пишите __flash. У Viko константы были размещены во флэш потому что он пользовался компилятором для ARM.
|
|
|
|
|
Jan 14 2014, 13:10
|
Профессионал
    
Группа: Свой
Сообщений: 1 351
Регистрация: 21-05-10
Пользователь №: 57 439

|
Вот документ. На странице 5 есть информация о размещении констант в памяти. http://netstorage.iar.com/SuppDB/Public/SU...memoryusage.pdfКонстанты могут находиться в програмной памяти, оперативной памяти и внешней ЕПРОМ. А здесь на странице 6 утверждают: CONST Holds variables declared as const ....... The CONST and CSTR should only be included in the XLINK file if there is an external PROM in the system. http://www.atmel.ca/Images/doc1079.pdfЯ уже не помню, а копаться лень. Для доступа ко внешней ЕПРОМ и для доступа ко внутренней ОЗУ используются одинаковые команды на ассемблере? Если разные, то это может объяснить многое в декларации функции с константным параметром. Примечание: Я прекрасно знаю стандартное объяснение константного указателя как параметра функции, однако это всем известно. Разные способы адресации же это довольно неочевидное свойство.
Сообщение отредактировал Tarbal - Jan 14 2014, 13:38
|
|
|
|
|
Jan 14 2014, 18:09
|

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

|
Цитата(Tarbal @ Jan 14 2014, 15:10)  Вот документ. Опустим тот факт, что это документ лохматого года, когда ИАР знал только 6 моделей AVR. Цитата(Tarbal @ Jan 14 2014, 15:10)  А здесь на странице 6 утверждают:CONST Holds variables declared as const Ненаказуемо. Цитата(Tarbal @ Jan 14 2014, 15:10)  ....... The CONST and CSTR should only be included in the XLINK file if there is an external PROM in the system. Я уже не помню, а копаться лень. Для доступа ко внешней ЕПРОМ и для доступа ко внутренней ОЗУ используются одинаковые команды на ассемблере? Если разные, то это может объяснить многое в декларации функции с константным параметром. Если повесите свою параллельную ПЗУ на внешнюю шину как память данных - команды будут одинаковые. Но опять же, это не компилятор положит во флеш, а вы запихнете ПЗУ в адресное пространство ОЗУ, этакое чесание левого уха правой ногой. Обе эти памяти будут находиться в одном адресном пространстве. Обратите внимание на свой же документ: Цитата Table comments: (*) Each combination of processor option and memory model has a default memory type, and also one or more additionally available memory types. All constant and variable data which are put into the segments CCSTR, ECSTR, CSTR, CONST and CSTACK are always implicitly belonging to the default memory type. Также обратите внимание, что в этой таблице все константы, не имеющие спецификатора flash имеют сноску номер 2, которая гласит: Цитата The initialized information is copied from program to data memory at startup. This is done in the ?C_STARTUP function in CSTARTUP.S90. The application accesses the variable in the data space. The used program space is never accessed after startup is fulfilled Дальше будете спорить?
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jan 14 2014, 18:46
|
Профессионал
    
Группа: Свой
Сообщений: 1 351
Регистрация: 21-05-10
Пользователь №: 57 439

|
Цитата(demiurg_spb @ Jan 14 2014, 20:34)  К тому что ваши ссылки, как собственно и измышления, исключительно для IAR. Но ведь есть и другие, более распространённые компиляторы, где const не гарантирует размещения данных в ПЗУ, что никак не противоречит стандарту. Об этом вам Сергей пытался намекнуть... Я допускаю, что вы невнимательно читали то что я писал. Опять же ваши замечания о GCC мимо кассы, поскольку стартовый постинг был про Кейл. О стандарте: Сколько я знаю компиляторов, у каждого есть свои особенности. Цитата(Сергей Борщ @ Jan 14 2014, 22:09)  Если повесите свою параллельную ПЗУ на внешнюю шину как память данных - команды будут одинаковые. Но опять же, это не компилятор положит во флеш, а вы запихнете ПЗУ в адресное пространство ОЗУ, этакое чесание левого уха правой ногой. Обе эти памяти будут находиться в одном адресном пространстве. Я это допускал, поэтому в предпоследнем постинге и написал: "Я уже не помню, а копаться лень. Для доступа ко внешней ЕПРОМ и для доступа ко внутренней ОЗУ используются одинаковые команды на ассемблере? Если разные, то это может объяснить многое в декларации функции с константным параметром." Цитата(Сергей Борщ @ Jan 14 2014, 22:09)  Обратите внимание на свой же документ: Table comments: (*) Each combination of processor option and memory model has a default memory type, and also one or more additionally available memory types. All constant and variable data which are put into the segments CCSTR, ECSTR, CSTR, CONST and CSTACK are always implicitly belonging to the default memory type. Мне это ничего не говорит в контексте нашей дискуссии. Цитата(Сергей Борщ @ Jan 14 2014, 22:09)  Дальше будете спорить? Я не спорю, а ищу ответы.
|
|
|
|
|
Jan 15 2014, 04:53
|
Знающий
   
Группа: Участник
Сообщений: 837
Регистрация: 8-02-07
Пользователь №: 25 163

|
Ну вот я собрал ваш код при помощи IAR AVR 5.3. Вот MAP файл: Код FILE NAME : D:\projects\avr\just_test\Debug\Obj\main.r90 PROGRAM MODULE, NAME : main
SEGMENTS IN THE MODULE ====================== NEAR_I Relative segment, address: DATA 000000A0 - 000000A5 (0x6 bytes), align: 0 Segment part 7. Intra module refs: main ENTRY ADDRESS REF BY ===== ======= ====== str1 000000A0 ------------------------------------------------------------------------- NEAR_I Relative segment, address: DATA 000000A6 - 000000AB (0x6 bytes), align: 0 Segment part 10. Intra module refs: main ENTRY ADDRESS REF BY ===== ======= ====== str2 000000A6 ------------------------------------------------------------------------- NEAR_Z Relative segment, address: DATA 000000AC - 000000AD (0x2 bytes), align: 0 Segment part 12. Intra module refs: main ENTRY ADDRESS REF BY ===== ======= ====== ptr 000000AC ------------------------------------------------------------------------- CODE Relative segment, address: CODE 00000054 - 000000A3 (0x50 bytes), align: 1 Segment part 14. ENTRY ADDRESS REF BY ===== ======= ====== main 00000054 ?cstartup_call_main (?C_STARTUP) RSTACK = 00000000 ( 00000002 )
|
|
|
|
|
Jan 15 2014, 07:37
|

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

|
Цитата(Tarbal @ Jan 14 2014, 20:46)  О стандарте: Сколько я знаю компиляторов, у каждого есть свои особенности. Да, особенности есть. Но вам уже третью страницу объясняют, что к const это не относится. Требование стандарта к const одно - компилятор должен выдавать ошибку при попытке записи в такую переменную. Все. В остальном эта обычная переменная. Далее ход мыслей у всех компиляторописателей обычно одинаков: разместить переменные с похожими свойствами (обнуляемые, инициализируемые и т.д.) рядом, чтобы при старте (если нужно) подготовить каждую группу к работе одним махом в цикле. Отсюда группирование переменных в сегменты. Никаких требований на размещение во флеш/ОЗУ для const стандарт на компилятор не накладывает, но и не запрещает, если это не мешает выполнению остальных требований стандарта. В случае разных адресных пространств (AVR) размещение констант в программной памяти (флеше) нарушает требование быть обычной переменной. Поэтому для размещения в других адресных пространствах (одно из которых - память кода) вводятся расширения - ключевые слова типа __flash, __eeprom, idata, xdata, far, huge и подобные. const совершенно перпендикулярен к этому. Если же архитектура имеет только одно адресное пространство, то появляется возможность работать с константами прямо во флеш не нарушая требования стандарта без всяких дополнительных ключевых слов, сэкономив таким образом ОЗУ и немножко времени на копировании при старте. И тут уже все в руках программиста - использовать такую возможность или нет. const снова никоим образом на это не влияет. Я показывал, что изменением положения одной строки в скрипте линкера можно получить вариант с константами в ОЗУ и константами во флеше. Оба варианта будут работать. И оба не нарушают стандарт. Цитата(Tarbal @ Jan 14 2014, 20:46)  Мне это ничего не говорит в контексте нашей дискуссии. default memory - ОЗУ. Содержимое всех указанных сегментов по умолчанию попадает в адресное прстранство ОЗУ. В том числе и сегмент CONST. Если это вам ни о чем не говорит - я не вижу смысла в дальнейшей дискуссии.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jan 15 2014, 13:13
|
Профессионал
    
Группа: Свой
Сообщений: 1 351
Регистрация: 21-05-10
Пользователь №: 57 439

|
Цитата(andrewlekar @ Jan 15 2014, 08:53)  Ну вот я собрал ваш код при помощи IAR AVR 5.3. Вот MAP файл: Спасибо. Убедили. Практика критерий истины  Цитата(Сергей Борщ @ Jan 15 2014, 11:37)  default memory - ОЗУ. И как это следует из вашей цитаты? ОЗУ насколько мне известно называется ОЗУ, а не default memory. Почему не написано ОЗУ если это одно и то же? С какой стати множить понятия?
Сообщение отредактировал Tarbal - Jan 15 2014, 13:14
|
|
|
|
|
Jan 15 2014, 13:49
|

Adept
     
Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343

|
Очень плотно использовал IAR для AVR в конце девяностых (незабвенная версия 1.40) и до середины нулевых, в т.ч. и лицензионные. Никогда объекты, квалифицированные как const, не попадали там во флешь и не могли попасть ни при каких обстоятельствах (вендор компилятора, версия компилятора, фаза луны и прочее). Этот результат жёстко определяется двумя обстоятельствами: 1. требованиями языков C/C++; 2. Архитектурой МК AVR.
1. Языки C/C++ без расширений не поддерживают никаких адресных пространств, кроме одного, т.е. все объекты программы "живут" в одной и тоже памяти, в едином адресном пространстве. Как физически эта память выполнена - это уже дело пятое, но адресное пространство должно быть одно. Соответственно, константные объекты могут жить только в этой памяти, т.е. в той же самой, что и все остальные объекты. В частности, к ним на равных правах применяются те же правила взятия адресов, адресной арифметики и т.д.
2. Архитектура МК AVR предусматривает раздельные адресные пространства для памяти данных и памяти программ. Память данных - ОЗУ, память программ - ПЗУ (флешь). Для того, чтобы разместить объект во флеши, его приходится совать в память программ, т.е. в другое адресное пространство. Для этого производитель компилятора IAR предусмотрел расширение языка ключевым словом __flash.
Объекты, квалифицированные ключевым словом const, никак не могут попасть в память программ. Если нужно засунуть объект во флешь, то приходится его размещать в памяти программ, но это уже не const объект, а __flash. Вот если бы у МК AVR ещё был сегмент памяти данных, выполненный в виде флеши, то тогда было бы возможно размещать во флеши (именно в этой флеши, а не во флеши памяти программ) константные объекты. Но таких МК, как помню, не было и, вроде, до сих пор нет.
У AVR, кстати, не два, а целых три адресных пространства - ещё есть EEPROM, сюда применимы все вышеприведённые рассуждения.
Таким образом, константные объекты у МК AVR могут жить только в памяти данных и это ОЗУ. Не нужно никаких экспериментов, чтобы прийти к этому выводу. Объекты, размещённые в других адресных пространствах - __flash, __eerpom, живут сами по себе и не могут напрямую использоваться, например, для операций адресной арифметики, производимой над обычными объектами.
--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
|
|
|
|
|
Jan 16 2014, 23:40
|
Профессионал
    
Группа: Свой
Сообщений: 1 351
Регистрация: 21-05-10
Пользователь №: 57 439

|
Цитата(dxp @ Jan 15 2014, 17:49)  Очень плотно использовал IAR для AVR в конце девяностых (незабвенная версия 1.40) и до середины нулевых, в т.ч. и лицензионные. Никогда объекты, квалифицированные как const, не попадали там во флешь и не могли попасть ни при каких обстоятельствах (вендор компилятора, версия компилятора, фаза луны и прочее). Этот результат жёстко определяется двумя обстоятельствами: 1. требованиями языков C/C++; 2. Архитектурой МК AVR.
1. Языки C/C++ без расширений не поддерживают никаких адресных пространств, кроме одного, т.е. все объекты программы "живут" в одной и тоже памяти, в едином адресном пространстве. Как физически эта память выполнена - это уже дело пятое, но адресное пространство должно быть одно. Соответственно, константные объекты могут жить только в этой памяти, т.е. в той же самой, что и все остальные объекты. В частности, к ним на равных правах применяются те же правила взятия адресов, адресной арифметики и т.д.
2. Архитектура МК AVR предусматривает раздельные адресные пространства для памяти данных и памяти программ. Память данных - ОЗУ, память программ - ПЗУ (флешь). Для того, чтобы разместить объект во флеши, его приходится совать в память программ, т.е. в другое адресное пространство. Для этого производитель компилятора IAR предусмотрел расширение языка ключевым словом __flash.
Объекты, квалифицированные ключевым словом const, никак не могут попасть в память программ. Если нужно засунуть объект во флешь, то приходится его размещать в памяти программ, но это уже не const объект, а __flash. Вот если бы у МК AVR ещё был сегмент памяти данных, выполненный в виде флеши, то тогда было бы возможно размещать во флеши (именно в этой флеши, а не во флеши памяти программ) константные объекты. Но таких МК, как помню, не было и, вроде, до сих пор нет.
У AVR, кстати, не два, а целых три адресных пространства - ещё есть EEPROM, сюда применимы все вышеприведённые рассуждения.
Таким образом, константные объекты у МК AVR могут жить только в памяти данных и это ОЗУ. Не нужно никаких экспериментов, чтобы прийти к этому выводу. Объекты, размещённые в других адресных пространствах - __flash, __eerpom, живут сами по себе и не могут напрямую использоваться, например, для операций адресной арифметики, производимой над обычными объектами. Вы правы. Я подзабыл. Они в ЕЕПРОМ располагались. Цитата(Сергей Борщ @ Jan 15 2014, 19:23)  default memory - память, в которую попадают "обычные" переменные. Куда они могут попасть кроме как в ОЗУ? Неужели и это надо было разжевать? Я не считаю что это очевидно.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|