ВходНаше всё Теги codebook PARTS Поиск Опросы Закон Пятница
12 августа
1035467 Топик полностью
Связанные сообщения
Code StyleMacroFk0
есть метод енум в строку преобразовать?2022-07-12
Вчерне получилось, так вот2022-07-06
Процитирую сам себя: "Разработка ПО большого объёма на языках с динамической типизацией, как правило затруднена, но в целом скор...2020-10-30
Тебе не нужен STM32 + "Си". Тебе нужен Си отдельно и STM32, если вообще нужен, отдельно. Кусочно-выборочно процитирую сам себя: ...2020-09-10
Есть мысль перейти на RTOS для снижения временных затрат на реализацию программной части, отладку и профилировку. Важна поддержк...2020-06-18
Пользуйся:2020-06-11
Надо понимать, что класс -- это не структура. Применительно к C++ мне больше нравится слово тип. Тип -- это сущность существующа...2020-04-26
Можно просто енумы генерировать через макрос, который сгенерирует и энум, и inline-функцию принимающую данный enum и возвращающу...2019-12-11
К сожалению openwatcom реально стар. Это код для условно современного C-компилятора, поддерживающего C99. У openwatcom не полноф...2019-12-11
Процитирую самого себя: "Зачем вообще использовать "экспоненциальное скользящее среднее", кроме как от бедности (не хватает ресу...2019-11-01
Выскажу ещё раз: FreeRTOS сырая недоделка, смысла особого, без реализации ряда перечисленного (см. ниже) не имеет и, хуже того, ...2019-10-18
Это вопрос кодстайла. Очень удобна, например, венская конвенция венгерская нотация. LpZStrЁклмн ведь куда понятнее, чем п...2019-03-14
Я на нечто подобное нарывался. Теперь вся отладка складывается в FIFO, только потом ее обрабатываю.2017-11-24
Топик посвящён программированию микроконтроллеров в условиях необходимости экономии электроэнергии и архитектуре ПО в целом.2011-10-24
fk0, легенда (11.09.2020 03:09, просмотров: 629) ответил Aleksey_75 на )) оке
Классика жанра же: когда делаешь макрос, его всегда, кроме случаев когда невозможно, нужно делать выражением (а не оператором -- потому, что сам макрос могут вставить в контекст выражения, а не оператора), и обязательно брать в скобки тело макроса! И аргументы макроса тоже нужно брать в скобки, потому, что в общем случае неизвестно с каким аргументами вызывали макрос, может там MACRO(a+b, a*b), и неизвестно как оно состыкуется с операторами в макросе. 

Пример:


 #define MACRO(x, y) ((x)+(y))


Кроме того, если в макрос передаются аргументы-переменные например (любые идентификаторы или типы на самом деле), они могут конфликтовать с переменными или типами продекларированными в теле макроса (это если макрос таки не выражение, а оператор, или если макрос на C++ и содержит лямбду, или если макрос на GCC и содержит statement expressions). Поэтому декларировать что-то внутри макроса лучше с какими-нибудь префиксами/суффиксами, а не просто A или Б.


Пример:


#define MACRO(count, f) do { 
        int n__ = count; \
        do f(n__) while (--n__); \
} while(0)

// MACRO(n__,f) gives an error because of name clashing.


Здесь так же показано, что макросы являющиеся оператором стоит обязательно включить в блок кода (фигурные скобки), который может быть внутри "do {} while(0)", что позволит в конце макроса вставить точку с запятой. Если без do/while то в таком варианте будет ошибка:


int g(void);
int f(void);

// this gives an error:
#define MACRO() { g(); }

// this compiles without error
//#define MACRO() do { g(); } while(0)

int main(int ac, char *av[])
{
    (void)av;
    
    if (ac)
       MACRO();
    else
       f();
       
    return 0;   
}

main.cpp:17:5: error: 'else' without a previous 'if'
   17 |     else
      |     ^~~~


https://coliru.stacked-crooked.com/a/6fee23d2ad027e9e



Пример макроса для GCC:


#define MACRO(n, f) ({ \
        int n__ = n; \
        do f(n__) while (--n__); \
})


Последний макрос можно использовать внутри выражения, а не вместо оператора -- иногда это жизненно необходимо. И этот макрос может вернуть значение (равное значению последнему выражению в фигурных скобках). Ну в gcc ещё в теле такого макроса можно функцию определить и вызвать её, только указатель на такую функцию не стоит возвращать из макроса -- программа навернётся. И такой код, если он адресует внешние переменные (по отношению к функции/макросу) не будет работать на системах с неисполняемым стеком (где GCC размещает свой трамплин). Если не прав, то прошу поправить.


Чтобы избежать дальнейших конфликтов имён обычно придерживаются некого code style, например:


1) макросы именуются строго заглавными буквами: #define MACRO(x, y) ((x)+(y))

2) типы обозначаются в CamelCase (PascalStyle): typedef struct S { ... } MyType;

3) объекты именуются в snake_case или в lowerCamelCase : MyType my_object или MyType myObject;

4) функции именуются в snake_case или lowerCamelCase тоже (функцию легко перепутать с конструктором типа в C++ обычно...);


См. также: http://caxapa.ru/910140


Примеры сложных макросов:

http://caxapa.ru/964034

http://caxapa.ru/964114


Расширения GCC:

https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html

https://gcc.gnu.org/onlinedocs/gcc/Nested-Functions.html

[ZX]