Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: void const *argument
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
Страницы: 1, 2
ViKo
В Keil CMSIS-RTOS RTX в параметрах задач указано:
Код
void job1 (void const *arg)

Что это, зачем? Писал, не задумываясь. Теперь хочу просветиться.
megajohn
ну к примеру у вас на контроллере два UART

и в одном проекте на modbus реализован на UART0 9600 а на UART1 модем AT 115200

а в другом проекте modbus реализован на UART1 19200 а на UART0 модем AT 36000

а задачи одинаковые.

тогда для проекта 1

typedef struct{
int port;
int speed;
}Suart_init;

const Suart_init mb_cfg = { 0, 9600 };
task_start( mb_task, ..., (void*)mb_cfg );

где

void mb_task( void const* arg )
{
Suart_init* arg_p = (Suart_init*)arg;
uart_open( arg_p->port, arg_p->speed );
...
}



то есть как реально в RTX синтаксис вызова не в курсе, но суть передал - вызов задач с конкретными параметрами.
kosyak©
Вот зачем оно конст...?
megajohn
если оно будет на стеке, то по моменту запуска самой задачи естветсвено всё уплывет.

то есть так нельзя
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 );
ViKo
Цитата(megajohn @ Jan 6 2014, 22:57) *
то есть как реально в RTX синтаксис вызова не в курсе, но суть передал - вызов задач с конкретными параметрами.

Спасибо! Понял. Проверил в действии. Работает.

Нужно поправить - брать адрес структуры.
Код
task_start( mb_task, ..., (void*)&mb_cfg );
kosyak©
тогда уж
task_start( mb_task, ..., (void const*)&mb_cfg );
sm.gif
GetSmart
Вообще-то компилятор должен "съедать" этот параметр при вызове функции и без явного преобразования. Как и для параметра "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 );

Второй вариант тоже будет на стеке. Просто менять его значения нельзя будет.
ViKo
Цитата(GetSmart @ Jan 7 2014, 02:38) *
Какая разница в данном случае, с амперсандом или без? В случае когда голый идентификатор структуры без указания поля. Однозначнее, конечно, было бы с амперсандом, но на данный момент в Си оба варианта вроде бы одинаковые.

Возможно, в других языках варианты одинаковые. Но не в С. В C можно структуру передавать в функцию, именно, по значению, а не по ссылке. Т.е., имя структуры не есть ее адрес. В отличие от массива.
GetSmart
Цитата(ViKo @ Jan 7 2014, 14:50) *
Возможно, в других языках варианты одинаковые. Но не в С.

Чем отличается результат двух вариантов выражений со структурами ниже?
Код
(void*)&mb_cfg
и
(void*)mb_cfg

Если отличаются, то в каких компиляторах.

Идентификатор/имя массива тоже не является адресом его первого элемента. Иначе выражение &mass было бы аналогом &(&mass[0]). Взятие адреса от адреса в Си допустимо?
ViKo
Цитата(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);
А в каком компиляторе работают оба? rolleyes.gif
megajohn
Цитата(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 );


да, мой косяк. Вместо компилятора под руками была текила, и это зло вчера меня победило
GetSmart
Цитата(ViKo @ Jan 7 2014, 16:18) *
Led9_id = osThreadCreate(osThread(Led_thread), (void *)led9);
А в каком компиляторе работают оба? rolleyes.gif

Предъявите объявление led9.
Проверьте для корректности все предыдущие версии Кейла. Если раньше оба варианта допускались, то как разработчики это обосновали и обосновали ли?

Цитата(megajohn @ Jan 7 2014, 16:20) *
если это AVR то будет во флеше,

То есть от компилятора не зависит?

Цитата(megajohn @ Jan 7 2014, 16:20) *
не знаю как в высших материях, но в дизамсе передается просто адрес. Задача компилятора - ругатся при попытке записи по const*

Я имел ввиду "проявит себя" на этапе компиляции. По сути то же самое. Вне тела функции наличие квалификатора const никак не ограничивает передачу параметров по сравнению с вариантом без квалификатора const (в прототипе функции).
ViKo
Цитата(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);
}
}

GetSmart
Цитата(ViKo @ Jan 7 2014, 16:18) *
Тем, что второй вариант не компилируется.
Keil V5.1.0

А (void *)&mass скомпилируется, если это идентификатор массива? Кейла 5-ого под рукой нет чтобы проверить. Идентификаторы массивов, структур и юнионов должны (были) отличаться в применении. При явном преобразовании адреса логично было бы чтобы выражение с идентификатором было приведено к адресу силами самого программиста, дабы не возникало неоднозначностей.

Жаль, в Си нет операторов детипизации указателей, сохраняя исходное адресное пространство. В идеале ещё как-то наследующих выравнивание и другие атрибуты. Вручную для безопасной работы приходится объявлять указатель на void и потом его присваивать к другому типизированному указателю.
ViKo
Цитата(GetSmart @ Jan 8 2014, 09:38) *
А (void *)&mass скомпилируется, если это идентификатор массива? Кейла 5-ого под рукой нет чтобы проверить.

Проверьте на том, что имеете.
Мое мнение - для массива &mass и mass - одно и то же. Особенность языка.
Сергей Борщ
Цитата(ViKo @ Jan 8 2014, 11:21) *
Мое мнение - для массива &mass и mass - одно и то же.
Не совсем. &mass[0] и mass - вот это одно и то же. Точнее mass неявно приводится к &mass[0].
GetSmart
Цитата(ViKo @ Jan 8 2014, 15:21) *
Проверьте на том, что имеете.
Мое мнение - для массива &mass и mass - одно и то же. Особенность языка.

В IARе я так много раз делал без замечаний. Но если 5-ый Keil ругается на явное преобразование адреса от имени структуры без амперсанда, то использование аналогичного синтаксиса к имени массива порождает другой глюк. Кейлу логично было бы запретить использование (void *)&mass. Иначе будут новые грабли.
ViKo
Цитата(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; тоже не ругается!
Сергей Борщ
Цитата(ViKo @ Jan 8 2014, 13:10) *
На uint16_t *parr = (uint16_t *)&arr; тоже не ругается!
Естественно. Вы же делаете явное приведение типа. В этом случае каждый сам себе злобный Буратина, а компилятор умывает руки - если вы его просите о таком, значит знаете, чего хотите.
ViKo
Цитата(Сергей Борщ @ Jan 8 2014, 21:11) *
Естественно. Вы же делаете явное приведение типа. В этом случае каждый сам себе злобный Буратина, а компилятор умывает руки - если вы его просите о таком, значит знаете, чего хотите.

Значит, компилятор "имеет представление" о том, что такое &arr. Почему же он неявное приведение не делает?
Ассемблерные команды получаются те же, что и для uint16_t *parr = arr;
Сергей Борщ
Цитата(ViKo @ Jan 8 2014, 20:30) *
Почему же он неявное приведение не делает?
Потому что таковы правила языка. Это называется "безопасность типов" (type safety). Он не даем вам случайно спутать теплое с мягким и мух с котлетами. Но и оставляет вам право сделать это, если вам это действительно нужно, через явное приведение типов.
Tarbal
В процессорах с Гарвардской архитектурой AVR, PIC, 8051 константы размещаются во флеше. Флеш расположен в другом адресном пространстве чем ОЗУ и используются другие ассемблерные команды для доступа. Разумно расположить константные массивы во флеше, поскольку если располагать их в ОЗУ, то будут использована и флеш тоже (откуда-то ведь будет инициализация читаться). Передавая такой параметр в функцию надо дать знать в каком пространстве памяти находится параметр, чтобы функция использовала правильные ассемблерные команды.
Для этого и используется слово const. Pic использует слово flash кажется, но это в микрочиповском компиляторе. С другими не работал не знаю.
Сергей Борщ
Цитата(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) досуп к переменным во флеше или в ОЗУ на чтение одинаков, поэтому именно в них возможно указать линкеру размещать константные переменные во флеше не загружая копию в ОЗУ. А можно указать хранить в ОЗУ и все будет как у больших машин.
Herz
Цитата(Сергей Борщ @ Jan 9 2014, 09:28) *
А вот в процессорах с единым адресным пространством (ARM, x86, MSP430) досуп к переменным во флеше или в ОЗУ на чтение одинаков, поэтому именно в них возможно указать линкеру размещать константные переменные во флеше не загружая копию в ОЗУ. А можно указать хранить в ОЗУ и все будет как у больших машин.

А каким образом это делается? Буквально в двух словах, если можно.
ViKo
Цитата(Сергей Борщ @ Jan 9 2014, 10:28) *
А вот в процессорах с единым адресным пространством (ARM, x86, MSP430) досуп к переменным во флеше или в ОЗУ на чтение одинаков, поэтому именно в них возможно указать линкеру размещать константные переменные во флеше не загружая копию в ОЗУ. А можно указать хранить в ОЗУ и все будет как у больших машин.

Есть способ - указать квалификатор static.
Код
static const uint8_t *SourTxt[] = {"Кан1", "Кан2"};

В ОЗУ этих строк не будет. Сразу будут читаться из флэш программы.
andrewlekar
При чём тут static вообще? На ARMах const в определении переменной заставляет компилятор (и линкер) размещать её во флэше. На AVR такое не работало из-за раздельного адресного пространства.
XVR
Использование ключевых слов static и/или const для управления размещением данных (будь то flash или еще что) - вещь на 100% зависящая от конкретного компилятора. Стандарт С/С++ вообще не знает о том, что такое flash и как в нее помещать данные sm.gif

Поэтом, прежде чем советовать что то типа
Цитата
Есть способ - указать квалификатор static.
В ОЗУ этих строк не будет. Сразу будут читаться из флэш программы.
стоит указать, для каких именно компиляторов это справедливо
andrewlekar
Цитата
для каких именно компиляторов

Ни для каких. static очевидно может изменяться во время выполнения программы и не может быть размещён во flash.
const размещает переменные во flash независимо от квалификатора static - актуально для IAR для ARM.
ViKo
Цитата(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 переписывается в ОЗУ, и уже из ОЗУ используется в функции. Лично сталкивался. И получал на форуме совет. И от кого, помню.
andrewlekar
Что, вашему компилятору не хватает ума разместить глобальную переменную во флэше? Или вы просто не пробовали?
Сергей Борщ
Цитата(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 к объявлению локальной переменной она перестает быть автоматической и может быть размещена во флеше, что вы и наблюдали. То есть никакой мистики тут нет и все происходит строго в рамках стандарта.
ViKo
Цитата(Сергей Борщ @ Jan 9 2014, 15:19) *
Я, кажется, понял в чем дело - вы имели дело с локальными переменными функции.

Да, с локальными строками.
Сергей Борщ
Цитата(ViKo @ Jan 9 2014, 14:24) *
Да, с локальными строками.
О. А тут все о глобальных переменных спорили wink.gif
Tarbal
Цитата(Сергей Борщ @ 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;
}
andrewlekar
Что вы этим гениальным кодом хотите проверить? В 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 только запрещает изменение перемнной не более того.

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

Код
void *const x;
-- константный указатель. Вы не можете изменить этот указатель, но можете изменить то, на что он указывает:
Код
*x = y;

Код
const void *const x;
-- константный указатель на константу. Вы не можете изменить ничего.
ViKo
Удостоверился в Кейл для глобальных переменных:
- const (и static const, естественно) размещаются и используются из flash,
- инициализированные переменные без квалификаторов (и volatile, естественно) при старте из flash переносятся в RAM и уже там используются.
Конкретно задавать нестандартные квалификаторы не вижу необходимости.
Сергей Борщ
Цитата(ViKo @ Jan 10 2014, 11:45) *
Удостоверился в Кейл для глобальных переменных:
Для процессора с линейным адресным пространством (ARM, Cortex).

Для x51 все запутаннее - там есть и медленные generic указатели (с отметкой об адресном пространстве в старшем байте и с генерацией кодов доступа ко всем пространствам при обращении по такому указателю) и указатели на конретное адресное пространство (с квалификаторами data, idata, xdata и т.д). Тут подробнее. Насколько помню, по умолчанию (без спецификатора адресного пространства) константы располагаются в памяти data, т.е. в непосредственно адресуемом ОЗУ.
С C166 не работал, не знаю, но судя по сегментированному адресному пространству тоже должны быть хитрости.
Для других процессоров Keil вроде как компиляторов не делает.
GetSmart
Цитата(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) |
                ...;
....
}

Вот здесь (во второй строке), спрашивается, компилятору хватит информации не облажаться.
ViKo
Цитата(GetSmart @ Jan 10 2014, 14:45) *
Ну и как это связано с явным преобразованием идентификатора структуры? Разве при этом недостаточно информации о том, что "заказчик" желает взять именно её адрес?

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

Как это - адрес у регистровой переменной? Ну, для PIC-ов, где все переменные - регистры, можно понять. А вы о каком процессоре говорите?
GetSmart
Цитата(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 и уже там используются.

Кейлов много. Нужно указывать версию и для какого процессора. А при неуказании, сперва проверить на всех компиляторах Кейл для разных процессоров sm.gif
ViKo
Цитата(GetSmart @ Jan 10 2014, 15:07) *
Ещё интересно, как Кейл интерпретирует такое выражение:
void *ptr;
ptr = mb_cfg; // структура из начала темы
Тоже, наверное, запретил. Хотя к массиву будет допустимо.

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

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

Цитата(GetSmart @ Jan 10 2014, 15:07) *
Обоснование Кейла не озвучено.

Cогласно языку C.
Tarbal
Цитата(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 и уже там используются.
Конкретно задавать нестандартные квалификаторы не вижу необходимости.


О чем я и твержу.
andrewlekar
Цитата
У кого есть IAR AVR?

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


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

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

Если константа на самом деле где-то может пригодиться, то можете делать глобальной. Все подряд делать глобальными не стоит - экспортируется много символов и размываются интерфейсы у модулей.
GetSmart
Цитата(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. Как не меняющий адресное пространство.
Tarbal
Цитата(andrewlekar @ Jan 10 2014, 21:30) *
Может уже хватит переливать из пустого в порожнее? То народ указатель на структуру от самой структуры отличить не может, то указатель на массив от самого массива, то общее адресное пространство от раздельного.


Ничего не понял. Может попробуете еще раз выразить свою мысль?
andrewlekar
Цитата
Ничего не понял. Может попробуете еще раз выразить свою мысль?


В вашем коде для AVR все переменные будут размещены в ОЗУ. Хотите их размещать во флэш - пишите __flash. У Viko константы были размещены во флэш потому что он пользовался компилятором для ARM.
Tarbal
Цитата(andrewlekar @ Jan 11 2014, 10:32) *
В вашем коде для AVR все переменные будут размещены в ОЗУ. Хотите их размещать во флэш - пишите __flash. У Viko константы были размещены во флэш потому что он пользовался компилятором для ARM.


Я вам не верю. Когда я в конце 90х работал с ним константы были размещены во флэш.
Сергей Борщ
Цитата(Tarbal @ Jan 11 2014, 20:22) *
Я вам не верю.
Ваше право. Но убеждать остальных на основании только лишь вашей веры как-то неразумно.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.