FOR_MACRO подскажите можно ли передать масив в качестве аргумента

Николай Ск

✩✩✩✩✩✩✩
28 Мар 2023
11
2
Задался вопросом можноли написать шапку для компилятора типа:
#
for (int i = 0; i <9; i++) {
Serial.print(i) ;
}#
А он сам бы при компиляции написал эти сточки в скетче указанное количество раз

В интернете нашёл только одну статью "Циклы" на препроцессоре, в другой теме мне подсказали что это макрос и надо писать

Начал просматривать библиотеки со слова макрос и boost и смотрю есть FOR_MACRO от AlexGyver читаю описание, а там почти так и написано это то, что ты ищешь и даже больше, что способен понять.

Так вот подскажите кто разбирается в библиотеке:
- если аргументы не нужны можно ли указать число повторений, числом (переменной), а не вписывать пустые аргументы вручную
-и можно ли указать массив или структуру с аргументами, а не вписывать аргументы вручную

C++:
#include <FOR_MACRO.h>

byte masiv [] = {5, 25, 35, 45};

void setup() {
  Serial.begin (115200);

  #define MF1(N, i, p, val)\
  Serial.print(N);
  #define FOR_1( ...) FOR_MACRO(MF1, 0, __VA_ARGS__)

  FOR_1(,,,,,,,,);      //развернется как  Serial.print(9);Serial.print(9);Serial.print(9);(9раз по числу аргументов в ())
  Serial.println();
}

void loop() {
  delay (1000);
  Serial.println();
  ///*
  #define MF2(N, i, p, val) Serial.print(i);
  #define FOR_2( ...) FOR_MACRO(MF2, 0, __VA_ARGS__)
  FOR_2(,,,,,,,,);      //развернется как  Serial.print(8);Serial.print(7);Serial.print(6);...
  //*/
  
  //если аргументы не нужны можно ли указать число повторений, числом (переменной), а не вписывать пустые аргументы вручную
  //можно ли указать массив или структуру с аргументами, а не вписывать аргументы вручную
  /*
  #define MF3(N, i, p, val) Serial.print(val);
  #define FOR_3( ...) FOR_MACRO(MF3, 0, __VA_ARGS__)
  FOR_3(*masiv);      //так вписывает один первый аргумент масива
  */

}
 
Изменено:

poty

★★★★★★✩
19 Фев 2020
3,452
985
@Николай Ск, если FOR_MACRO.h управляет препроцессором, то "обычный" массив в него не загнать. Препроцессор работает перед компиляцией, когда никакие переменные, включая массивы, ещё неизвестны. По сути препроцессор аналогичен функции замены текста в текстовом редакторе с незначительными автоматизациями. То есть непосредственно текст программы не анализируется.
 

Николай Ск

✩✩✩✩✩✩✩
28 Мар 2023
11
2
@poty, я не пытаюсь что-то доказать по тому, что мои знания это метод тыка но обрати пожалуйста внимание на часть скетча там в качестве аргумента массив. а результат - это первый элемент массива, поэтому я и посчитал что массив определен, и можно передать, просто я делаю что-то не так.

#define MF3(N, i, p, val) Serial.print(val);
#define FOR_3( ...) FOR_MACRO(MF3, 0, VA_ARGS)
FOR_3(*masiv); //так вписывает один первый аргумент масива
 

poty

★★★★★★✩
19 Фев 2020
3,452
985
@Николай Ск, аргументы вставляются в текст программы в виде текста, за исключением ранее определенных define, которые заменяются на их значения. Если есть действия с константами, то все они, по возможности, выполняются препроцессором.
 

Bruzzer

★★★✩✩✩✩
23 Май 2020
590
176
@Николай Ск,
Я уже писал раньше, что на макросах можно много что сделать, но для тех кто ими не пользуется, выглядит это малопонятно.
Я в макросах не разбираюсь.
Т.к. стандартно макросы не поддерживают циклы, то необходимо расписать ВСЕ варианты руками.
Если вы посмотрите FOR_MACRO.h , то увидите что там расписаны все варианты для максимально допустимого числа аргументов. С рекурсивным вызовом.
Если вам в качестве головоломки интересно изучать макросы, то смысл в этом может быть.
Если нет, то лучше обойтись без них.

Простейший вариант макроса для массива сделать легко (без рекурсии и авто подсчета количества).
Надо просто расписать все варианты.
Как пример. (Все, что между //начало и //конец , можно оформить в отдельный макрос, и вызывать его одной строчкой.)
Но повторюсь, я не спец в макросах, могу ошибаться.
Помогать написать макрос под ваши нужды не берусь.

C++:
#define N 10
String arrStr[N] = {"_0_", "_1_", "_2_", "_3_", "_4_", "_5_", "_6_", "_7_", "_8_", "_9_"};

void setup() {
  Serial.begin(9600);
  Serial.println("===START===");

// начало
#if N >= 1
  Serial.println(arrStr[0]);
#endif
#if N >= 2
  Serial.println(arrStr[1]);
#endif
#if N >= 3
  Serial.println(arrStr[2]);
#endif
// И так далее до максимально возможного значения
// Если когда то N может быть 100, то надо записать 100 вариантов
//конец
}

void loop() {
}
 

Николай Ск

✩✩✩✩✩✩✩
28 Мар 2023
11
2
Всем спасибо за помощь.
Разобрался в алгоритме работы макроса, убрал оттуда то, что мне не нужно, а именно то, ради чего его писали показать возможность работы другого макроса variadic. Оставил возможность разворачивается по заданному числу раз. В общем разобрал машину, собрал мопед, но для моих задач этого достаточно.

если кому интересно урезаный макрос
C++:
#pragma once
#define _FM_EXP(x) x
#define _FM_CONCAT(x, y) _FM_CONCAT_IMPL(x, y)
#define _FM_CONCAT_IMPL(x, y) x##y

#define _FM_FOR_1(f, N, p) f(N, 0, p)
#define _FM_FOR_2(f, N, p) f(N, 1, p) _FM_FOR_1(f, N, p)
#define _FM_FOR_3(f, N, p) f(N, 2, p) _FM_FOR_2(f, N, p)
#define _FM_FOR_4(f, N, p) f(N, 3, p) _FM_FOR_3(f, N, p)
#define _FM_FOR_5(f, N, p) f(N, 4, p) _FM_FOR_4(f, N, p)
//
  #define _FM_FOR_6(f, N, p) f(N, 5, p) _FM_FOR_5(f, N, p)
  #define _FM_FOR_7(f, N, p) f(N, 6, p) _FM_FOR_6(f, N, p)
  #define _FM_FOR_8(f, N, p) f(N, 7, p) _FM_FOR_7(f, N, p)
  #define _FM_FOR_9(f, N, p) f(N, 8, p) _FM_FOR_8(f, N, p)
  #define _FM_FOR_10(f, N, p) f(N, 9, p) _FM_FOR_9(f, N, p)
  #define _FM_FOR_11(f, N, p) f(N, 10, p) _FM_FOR_10(f, N, p)
  #define _FM_FOR_12(f, N, p) f(N, 11, p) _FM_FOR_11(f, N, p)
  #define _FM_FOR_13(f, N, p) f(N, 12, p) _FM_FOR_12(f, N, p)
  #define _FM_FOR_14(f, N, p) f(N, 13, p) _FM_FOR_13(f, N, p)
  #define _FM_FOR_15(f, N, p) f(N, 14, p) _FM_FOR_14(f, N, p)
  #define _FM_FOR_16(f, N, p) f(N, 15, p) _FM_FOR_15(f, N, p)
  #define _FM_FOR_17(f, N, p) f(N, 16, p) _FM_FOR_16(f, N, p)
  #define _FM_FOR_18(f, N, p) f(N, 17, p) _FM_FOR_17(f, N, p)
  #define _FM_FOR_19(f, N, p) f(N, 18, p) _FM_FOR_18(f, N, p)
  #define _FM_FOR_20(f, N, p) f(N, 19, p) _FM_FOR_19(f, N, p)
  #define _FM_FOR_21(f, N, p) f(N, 20, p) _FM_FOR_20(f, N, p)
  #define _FM_FOR_22(f, N, p) f(N, 21, p) _FM_FOR_21(f, N, p)
  #define _FM_FOR_23(f, N, p) f(N, 22, p) _FM_FOR_22(f, N, p)
  #define _FM_FOR_24(f, N, p) f(N, 23, p) _FM_FOR_23(f, N, p)
  #define _FM_FOR_25(f, N, p) f(N, 24, p) _FM_FOR_24(f, N, p)
  #define _FM_FOR_26(f, N, p) f(N, 25, p) _FM_FOR_25(f, N, p)
  #define _FM_FOR_27(f, N, p) f(N, 26, p) _FM_FOR_26(f, N, p)
  #define _FM_FOR_28(f, N, p) f(N, 27, p) _FM_FOR_27(f, N, p)
  #define _FM_FOR_29(f, N, p) f(N, 28, p) _FM_FOR_28(f, N, p)
  #define _FM_FOR_30(f, N, p) f(N, 29, p) _FM_FOR_29(f, N, p)
//

#define _FM_FOR_(N, f, p) _FM_EXP(_FM_CONCAT(_FM_FOR_, N)(f, N, p))
#define FOR_MACRO(f, N, p) _FM_FOR_(N, f, p)
пример использования
C++:
#include <FOR_MACRO3.h>    //название урезка макроса
#define kolvo 10   //количество развёртывания
#define MF2(N, i, p)\ 
byte a##i= i;
#define FOR_2() FOR_MACRO(MF2, kolvo, 0)
FOR_2();      //развернется как  byte a9= 9; byte a8= 8; byte a7= 7;...byte a0= 0;
 

Мишутк

✩✩✩✩✩✩✩
29 Мар 2025
36
6
Есть такой прием, называется граничный элемент. В конце массива записывается элемент с невозможным значением. Функция перебора работает с элементами пока не встретит последний невозможный среди массива. Позволяет обходиться без передачи размера.
Самый яркий пример - строка в C, null terminated string.
 

Kir

★✩✩✩✩✩✩
28 Мар 2020
71
17
@Мишутк,

Передача в функцию ссылки на массив произвольного размера в C++ это решается шаблонами
C++:
template<size_t N>
int TotalSum(int (&array)[N]) {
    int sum = 0;
    for(size_t i = 0; i < N; ++i) {
        sum += array[i];
    }
    return sum;
}
Этот пример можно преобразовать в весьма полезную функцию, которая определяет количество элементов произвольного массива
C++:
template<typename T, size_t N>
constexpr size_t IndexOf(T (&)[N]) {
    return N;
}
А если используется С++17, то можно ничего не придумывать, а использовать функцию std::size
Странно конечно, что для массивов ее так поздно добавили, ведь могли бы и в С++11 добавить, или даже в С++03, правда без constexpr.