LINUX.ORG.RU

Зачем нужен цикл в функциях STM32 HAL

 ,


0

2

Смотрю исходники STM32 HAL. Вижу следующее:

#define __HAL_RCC_GPIOC_CLK_ENABLE()  do { \
                                        __IO uint32_t tmpreg = 0x00U; \
                                        SET_BIT(RCC->AHB1ENR, RCC_AHB1ENR_GPIOCEN);\
                                        /* Delay after an RCC peripheral clock enabling */ \
                                        tmpreg = READ_BIT(RCC->AHB1ENR, RCC_AHB1ENR_GPIOCEN);\
                                        UNUSED(tmpreg); \
                                          } while(0U)

зачем здесь нужен do/while цикл? Выполняется он всегда ровно 1 раз, т.к. постусловие всегда ложно. Правильно ли я понимаю, что это нужно только для того, чтобы определить внутри цикла переменную tmpreg так, чтобы область ее видимости была в этом самом цикле и название переменной не конфликтовало с названиями внутри функции, которая вызывает макрос?

Это какая-то магия для сишных макросов, чтобы они не глючили.
ИМХО

Bad_ptr ★★★★★
()

Для ограничения области видимости переменной достаточно блока кода.

aiqu6Ait ★★★★
()

судя по коменту
Delay after an RCC peripheral clock enabling
цикл ждет запуска peripheral clock, который запускается длительное время, а OU, предположу, показывается что генератор запустился и точно работает.

pfg ★★★★★
()

Не только для переменной. Ещё для того, чтобы макрос снаружи вёл себя как функция в плане синтаксиса.

Если сделать без { } то будут неприятные сюрпризы в конструкциях типа

if(...) __HAL_RCC_GPIOC_CLK_ENABLE();

Если сделать { } но без do-while то после раскрывания из __HAL_RCC_GPIOC_CLK_ENABLE(); получится

{ ... };
(лишняя точка с запятой после скобки, тоже может испортить смысл конструкции местами).

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 1)
Ответ на: комментарий от pfg

не OU а 0U (ноль)

Это же классическая конструкция, повсеместно используется, никто её ни разу не видел что ли?

А delay там это чтение регистра.

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 2)

Платиновые треды ЛОРа.

anonymous
()

Чтоб можно было писать, например, if(…) __HAL_RCC_GPIOC_CLK_ENABLE else …;

anonymous
()
Ответ на: комментарий от Legioner

Так пишут только мудаки. При числе таких макросов более 25 будешь полдня искать где лишняя скобка или ее не хватает. Плавали знаем.

anonymous
()

Потому что do{}while() требует в конце точки с запятой. Т.е. вызывая макрос в разных местах, его вызов не будет нарушать синтаксис. Да, это один из многих Си-шных костылей.

BceM_IIpuBeT ★★☆☆☆
()
Последнее исправление: BceM_IIpuBeT (всего исправлений: 1)

Для определения блока можно было бы просто сделать блок через {}

do{xxx} while(0) используется чтобы получить корректную конструкцию при вызове макроса через

__HAL_RCC_GPIOC_CLK_ENABLE();

и не было предупреждений о лишнем ";"

mittorn ★★★★★
()
Последнее исправление: mittorn (всего исправлений: 1)

Еще так делают потому, что на самом деле ; — это оператор вычисления ради побочного эффекта, т.е. лишняя точка с запятой(или ее отсутствие) в некоторых местах может стрельнуть по ногам.

BceM_IIpuBeT ★★☆☆☆
()
Последнее исправление: BceM_IIpuBeT (всего исправлений: 1)

Это классика жанра. Читать например тут → https://hownot2code.com/2016/12/05/do-while-0-in-macros/

TL;DR:

do{…}while(0) is the only construct in C that lets you define macros that always work the same way, so that a semicolon after your macro always has the same effect, regardless of how the macro is used (with particularly emphasis on the issue of nesting the macro in an if without curly-brackets).

beastie ★★★★★
()
Последнее исправление: beastie (всего исправлений: 1)

Лучше бы спросил, накой тут это:

Delay after an RCC peripheral clock enabling … tmpreg = READ_BIT(…);

А ответ — оно тут нахер не нужно, но это же кал, в нём всё из одно места. Посмотри ещё что там в тех макросах наверчено.

anonymous
()

Это макромагия, чтобы макрос можно было использовать внутри if else

https://stackoverflow.com/questions/1067226/c-multi-line-macro-do-while0-vs-scope-block

Первый раз такие конструкции встретил в каких-то фрибсдшных исходниках, так что это классика, а не говнокод, как некоторые позволили себе выразиться по незнанке

IvanR ★★★
()
Последнее исправление: IvanR (всего исправлений: 2)
Ответ на: комментарий от IvanR

Первый раз такие конструкции встретил в каких-то фрибсдшных исходниках

Не удивлен. А ты знаешь, что bsd писали гомосексуалисты?

anonymous
()
Ответ на: комментарий от anonymous

гомосексуалисты

И что? Может быть человек со сменой ориентации глупеет? Вы вот, судя по вашему посту, поглупели без смены ориентации

IvanR ★★★
()
Ответ на: комментарий от IvanR

Не знаю. Но когда коллеги искали где косяк в 3 вложенных макросах, все говорили, что код писал гомосексуалист.

anonymous
()
Ответ на: комментарий от anonymous

Да и машину Тьюринга тоже один из них придумал..

Laz ★★★★★
()
Ответ на: комментарий от fsb4000

В C есть функции.

Ага, и даже в C inline есть. Только вот компилятор может встроить функцию, а может и не встраивать – как звезды лягут. А в программах для МК до сих пор иногда такты важны. А с макросом этот фрагмент всегда будет встраиваться и ни каких прологов-эпилогов дополнительных.

Так что ерунду аноним написал.

u-235
()
Ответ на: комментарий от anonymous

Всё программирование кроме машкодов – костыль. А если задуматься, то и машкоды – костыль.

anonymous
()
Ответ на: комментарий от u-235

Только Ржавый спасет этот Мир!

anonymous
()

Оборачивать макрос в do{}while(0) — нормальная практика. Представь, что ты определил макрос

#define MACRO(x)  somecmd1(); somecmd2(x); somecmd3()
И написал:
if(x > 0) MACRO(x);
А потом ловишь глюки, что somecmd2 и somecmd3 всегда срабатывают, вне зависимости от проверки!

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

anonymous
()
Ответ на: комментарий от Siborgium

Ни хрена оно не работает! Даже если ты напишешь static inline, gcc может взбрыкнуть, и не заинлайнить функцию!

Поэтому макросы - наше фсьо! Или писать на С++, чтобы компилятор на стадии препроцессора и подготовки кода все проверки делал.

То, как делают в opencm3 и калокубе — просто образцовый показатель, как НЕЛЬЗЯ программировать!

anonymous
()

Ааа, мои глаза! Эти рукожопые быдлокодеры вместо того, чтобы написать

RCC->AHB1ENR |= RCC_AHB1ENR_GPIOCEN;
замутили такую адову портянку!!! Пример, как нужно писать:
RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN | RCC_AHBENR_GPIOCEN | RCC_AHBENR_GPIOFEN;
(вообще, зачастую здесь даже не надо |= писать, если ты гарантированно не будешь эту функцию вызывать повторно).

anonymous
()

Интересно почему классический while(0) заменился на while(0U).

Наверное формальный coding style требует везде писать суффиксы размера, а оформлять такое в виде макросов вместо функций - не запрещает

GPFault ★★
()
Ответ на: комментарий от untitl3d

Многие вендовозы про gcc и слыхом не слыхивали! И про makefile’ы. Натыкал пункт мышей в меню - скомпилялось, натыкал другой - прошилось. Что это можно легким движением руки в консольке делать, они даже не подозревают!

anonymous
()
Ответ на: комментарий от Siborgium

Смотри. Вот исходник:

static inline __attribute__((always_inline)) int pow(int a, int b){
    if(b < 1) return 1;
    for(int i = 1; i < b; ++i) a *= a;
    return a;
}

int shit(){
    int r = pow(2, 3);
    r += pow(4, 5);
    r += pow(10, 3);
    return r;
}
А вот, что делает из этого gcc с опцией -Os:
    .file   "1.c"
    .text
    .globl  shit
    .type   shit, @function
shit:
.LFB1:
    .cfi_startproc
    movl    $10016, %eax
    ret
    .cfi_endproc
.LFE1:
    .size   shit, .-shit
    .ident  "GCC: (Gentoo 11.2.0 p1) 11.2.0"
    .section    .note.GNU-stack,"",@progbits
Т.е. тупо вычислило, что получится, и загнало результат. ОК, сделаем сложней:
int shit(int i, int j){
    int r = pow(i, j);
    r += pow(i+1, j+1);
    r += pow(i+3, j+2);
    return r;
}
Вот тут уже наинлаейнено циклов. В общем, и в этом случае мы можем получить не совсем то, что ожидаем!

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.