Чёртов С со своими массивами.

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Знатоки, мошт знает кто, как передать в функцию массив, инициализированный скобками сразу в месте вызова, типа так:

void myFunc(int *array){

....  работа с массивом 

}

и вызов   myFunc({5,10,15,20,25});  -  конструирование массива прям в месте вызова

пока не компилится, с ошибкой 

error: no matching function for call to 'myFunc(<brace-enclosed initializer list>)

Невозможно такое?    Не хочется лишнюю переменную заводить.  Вот так работает

int values[] = {5,10,15,20,25};

myFunc(values);

 

sadman41
Offline
Зарегистрирован: 19.10.2016
DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Спасибо, sadman.

да, как ни странна, так работает

typedef int array[2];
void foo( array ) {}  // Note: the actual signature is: void foo( int * )
int main() {
   foo( (array){ 1, 2 } );
}

хренпоймишто, а не язык.  теперь я на массивы разной длины буду разные typedef-ы писать.  

sadman41
Offline
Зарегистрирован: 19.10.2016

Сдается мне, что по времени набивания - что переменную завести, что тайпдефы делать...

 

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

sadman41 пишет:

Сдается мне, что по времени набивания - что переменную завести, что тайпдефы делать...

Вот именно. 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

DetSimen пишет:

да, как ни странна, так работает

typedef int array[2];
void foo( array ) {}  // Note: the actual signature is: void foo( int * )
int main() {
   foo( (array){ 1, 2 } );
}

хренпоймишто, а не язык.  теперь я на массивы разной длины буду разные typedef-ы писать.  

Не стоит. Работает далеко не всегда и не везде (зависит от опций компилятора). запросто нарвётесь на "error: taking address of temporary array"

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

да я уже понял, спасибо.  Не стоит ждать чуда от ... 

Толи С у меня какойта нечесный. Почему бы и не дать возможность конструировать константный массив прямо там где он нужен

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

DetSimen пишет:

да я уже понял, спасибо.  Не стоит ждать чуда от ... 

Толи С у меня какойта нечесный. Почему бы и не дать возможность конструировать константный массив прямо там где он нужен


а если перейти на ассемблер в том месте где надо, делу не поможет?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Да, нет проблем. 

У меня тут сейчас форум и совсем некогда, я могу потом подумать как это покрасивше сделать, но вот так точно будет работать везде (начиная с С++ 11, кончено), хотя и выглядит ужасно

void kaka( int *) {}
 
void setup(void) {
	kaka([](void)->int *{ static int _[] = {1,2,3}; return _; }());
	kaka([](void)->int *{ static int _[] = {1,2,3,4,5,6}; return _; }());
}

void loop(void){};

Собственно здесь массив константный и длина нигде не указывается, а длинность можно спрятать в тот же дифайн вот так, например

void kaka( int *) {}

#define ConstArray(...) [](void)->int *{ static int _[] = {__VA_ARGS__}; return _; }()
 
void setup(void) {
	kaka(ConstArray(1,2,3));
	kaka(ConstArray(1,2,3,4,5,6));
}

void loop(void){};
DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Ну и на том огромное спасибо, ЕвгенийПетрович.  Не буду Вас от форума отвлекать. 

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Да, проверил, жуткая черезжопица, но работает какнада.  Еще раз спасибо. 

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

ЕвгенийП пишет:

Да, нет проблем. 

У меня тут сейчас форум и совсем некогда, я могу потом подумать как это покрасивше сделать, но вот так точно будет работать везде (начиная с С++ 11, кончено), хотя и выглядит ужасно

void kaka( int *) {}
 
void setup(void) {
	kaka([](void)->int *{ static int _[] = {1,2,3}; return _; }());
	kaka([](void)->int *{ static int _[] = {1,2,3,4,5,6}; return _; }());
}

void loop(void){};

Собственно здесь массив константный и длина нигде не указывается, а длинность можно спрятать в тот же дифайн вот так, например

void kaka( int *) {}

#define ConstArray(...) [](void)->int *{ static int _[] = {__VA_ARGS__}; return _; }()
 
void setup(void) {
	kaka(ConstArray(1,2,3));
	kaka(ConstArray(1,2,3,4,5,6));
}

void loop(void){};

$))))))

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

----

Респект! С лямбдой - изящно! На "чистом" С просто делаешь функцию ConstArray(), от неизвестного числа аргументов, которая возвращает массив. Но память все равно буде отведена и в ОЗУ и в програм-спейсе.

---

ЗЫ: вдруг задумался о таком же, "но с перламутровыми пуговицами". В том смысле, чтобы передать в функцию прогмем указатель, никак не трогая ОЗУ.... Здесь VA_ARGS не поможет... сходу - не могу придумать... может Женя что-то изобретет?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Влад, только не на этой неделе. Тут форум начался. Первый день - молодёжная конференция. Сейчас слушал обалденный доклад. Представляешь, распараллеливающий компилятор, который для пущей оптимизации допускает использование неэквивалентных преобразований программ. При этом, встретив неэквивалентность, он вступает в диалог с программистом, поясняя суть неэквивалентности, что можно выиграть от преобразования и нагло заявляя, что сам он (компилятор) не в состоянии гарантировать, что здесь всё будет нормально и спрашивает у программиста разрешения провести преобразование. Т.е. такая диалоговоая оптимизация в кооперации компилятора и программитса. И докладывала это юная девочка из Ростова (Южный Федеральный Университет). Я слушал и охреневал, вспоминая наши бесчисленные "Компилятор ругается, памагите"! В общем, я в восторге, давно пора было в рамках форума молодёжку проводить - в этом году впервые сподобились.

sadman41
Offline
Зарегистрирован: 19.10.2016

Капец. Все форумы будут завалены "У меня тут канпилятор спрашивает <....> . Я сам повар, срочно памагите, котлеты горят."

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Вот и я ж про тоже :)))

sadman41
Offline
Зарегистрирован: 19.10.2016

Кстати, спросите там, на фуршете, - допускает ли концепция компилятора ответ программиста "наверное" или "пох...".

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

:)

Был бы парень. У девочки не буду :)))

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Я сколько уже твержу о девочках, не слышат )))

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

О самих девочках или о компиляторах для девочек?

MaksVV
Offline
Зарегистрирован: 06.08.2015

а как узнать размер прилетевшего массива в функции kaka? Почитал, вроде как размер нужно передавать отдельным параметром.


byte _s;
#define ConstArray(...) [](void)->byte *{ static byte _[] = {__VA_ARGS__}; _s = sizeof(_); return _; }()
 
void setup(void) {
  Serial.begin(9600);
  kaka(_s, ConstArray(1,2,3,4,5,6));
}

void loop(void){};

void kaka(byte siZe, byte *vata) {Serial.print (siZe);}

хотя зачем передавать, если переменная размера глобальная. Сразу её использовать в функции. Так вроде работает. На сколько это коряво? 


byte siZe=0;
#define ConstArray(...) [](void)->byte *{ static byte _[] = {__VA_ARGS__}; siZe = sizeof(_); return _; }()
 
void setup(void) {
  Serial.begin(9600);
  kaka(ConstArray(1,2,3,4,5,6));
}

void loop(void){};

void kaka(byte *vata) {for(int i=0; i<siZe; i++) {Serial.print (vata[i]); Serial.print (" ");}}

 

a5021
Offline
Зарегистрирован: 07.07.2013

Совсем в лоб можно и так:

Другой вариант -- пишем значения прямо в строке в текстовом виде: myFunc("5,10,15,20,25"); а внутри функции тупо парсим строку.

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

MaksVV пишет:

а как узнать размер прилетевшего массива в функции kaka? Почитал, вроде как размер нужно передавать отдельным параметром.

Ну, таки, да, если нет ограничивающего символа, или нет возможности первым элементом массива длину передать

MaksVV пишет:

хотя зачем передавать, если переменная размера глобальная. Сразу её использовать в функции. Так вроде работает. На сколько это коряво? 

Не, ну, а за что боролись? Если можно пользовать глобальные, так и массив можно не передавать. Да и если надо использовать ConstArray не один раз, а десять, будете десять глобальных заводить?

Можно, например, сделать точно таким же приёмом, как и раньше (повторяю, это первое, что сразу идёт "на пальцы", применять голову на этой неделе не могу).

#include <Printing.h>

void kaka(const size_t size, int *arr) {
	printf("Size=%d\n", size);
	for (size_t i = 0; i < size; printf("%d ", arr[i++]));
	putchar('\n');
}

#define ConstArray(...)  [](void)->size_t{ int _[] = { __VA_ARGS__}; return sizeof(_)/sizeof(_[0]); }(),[](void)->int *{ static int _[] = { __VA_ARGS__}; return _; }()

void setup(void) {
	Serial.begin(115200);
	kaka(ConstArray(1, 2, 3));
	kaka(ConstArray(1, 2, 3, 4, 5, 6));
}

void loop(void){};

//----------------------------
//	Результат
//
//	Size=3
//	1 2 3 
//	Size=6
//	1 2 3 4 5 6 

Не бойтесь первого __VA_ARGS__, в дефайне, он не жрёт память, его оптимизатор просто выбросит, а вставит туда готовую константу.

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

нет, решение очень хорошее, спасибо, применяю.  Размер передаю отдельно, а два разнотиповых, но взаимосвязанных константных массива - отдельно

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

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

#include <Printing.h>

void kaka(const size_t size, const int *arr) {
	printf("Size=%d\n", size);
	for (size_t i = 0; i < size; printf("%d ", arr[i++]));
	putchar('\n');
}

#define ConstArray(...)  [](void)->size_t{ const int _[] = { __VA_ARGS__}; return sizeof(_)/sizeof(_[0]); }(),[](void)->const int *{ const static int _[] = { __VA_ARGS__}; return _; }()

void setup(void) {
	Serial.begin(115200);
	kaka(ConstArray(1, 2, 3));
	kaka(ConstArray(1, 2, 3, 4, 5, 6));
}

void loop(void){};

//----------------------------
//	Результат
//
//	Size=3
//	1 2 3 
//	Size=6
//	1 2 3 4 5 6 

 

MaksVV
Offline
Зарегистрирован: 06.08.2015

ЕвгенийП пишет:

Не, ну, а за что боролись? Если можно пользовать глобальные, так и массив можно не передавать. Да и если надо использовать ConstArray не один раз, а десять, будете десять глобальных заводить?

эмм, ну вроде ж переменная всегда обновляется в функции ConstArray и при её использовани в  функции kaka она получается актуальна. Зачем их несколько?

Вот так работает норм. Или я чего то не понял? 


byte siZe=0;
#define ConstArray(...) [](void)->byte *{ static byte _[] = {__VA_ARGS__}; siZe = sizeof(_); return _; }()
 
void setup(void) {
  Serial.begin(9600);
  kaka(ConstArray(1,2,3,4,5,6));
   kaka(ConstArray(1,2));
    kaka(ConstArray(1,2,3,4));
}
void loop(void){};

void kaka(byte *vata) {for(int i=0; i<siZe; i++) {Serial.print (vata[i]); Serial.print (" ");} Serial.println();}

хотя за более граммотный пример спасибо!

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

MaksVV пишет:

эмм, ну вроде ж переменная всегда обновляется в функции ConstArray и при её использовани в  функции kaka она получается актуальна. Зачем их несколько?

Так Вы её ещё и обновляете? Обновлять глобальные переменные в функции - это нужно иметь веские причины. Без крайней нужды это делать - очень дурной тон.

Я объясню почему, но не этом примере - он слшком тривиален.

Вот, предположим, есть некая функция kaka, которая не void, а возвращает значение. Значение она как-то вычисляет, короче оно зависит от некой глобальной переменной. И при этом, в процессе вычислений, функция ещё и меняет эту глобальную переменную, на будущее. Понятен пример?

mumu (kaka(5), kaka(10));

Т.е. значения, которые вернут каки передаёте другой функции. Что будет с Вашей глобальной переменной? Очевидно, что обе каки её будут менять. В каком порядке? Сначала левая, а потом правая или наоборот? От этого ведь зависит результат - кто из них первым глобальную переменную поменяет.

Так вот, ответа на этот вопрос нет - порядок вычисления аргументов в языке неопределён. А, значит, работоспособность кода будет зависеть от конкретного компилятора, а может и от его версии.

Это только один пример. Можно привести ещё много. Но общая идея - без крайней нужды не менять никчего в глобальном контексте - она всегда остаётся в силе. Менять можно, когда без этого никак не обойтись и при этом очень внимательно следить, чтобы не нарваться на неоднозначности.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

ЕвгенийП пишет:

Так вот, ответа на этот вопрос нет - порядок вычисления аргументов в языке неопределён. А, значит, работоспособность кода будет зависеть от конкретного компилятора, а может и от его версии.

Удивили!!! А мне думалось вытворяй что хочешь, вот я и вытворял )))

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

это С, детка.  На каждой странице стандарта можно встретить надпись "undefined behavior".  :) 

MaksVV
Offline
Зарегистрирован: 06.08.2015

ЕвгенийП пишет:

Т.е. значения, которые вернут каки передаёте другой функции. Что будет с Вашей глобальной переменной? Очевидно, что обе каки её будут менять. В каком порядке? Сначала левая, а потом правая или наоборот? От этого ведь зависит результат - кто из них первым глобальную переменную поменяет.

Так вот, ответа на этот вопрос нет - порядок вычисления аргументов в языке неопределён. А, значит, работоспособность кода будет зависеть от конкретного компилятора, а может и от его версии.

супер, прям в точку. А я думаю, почему сначала не заработало, когда я в верхнем примере #19, аргументы функции поставил сперва так, а потом , поменяв их местами, стало адекватно работать. 

Ошибку понял. Как всегда очень познавательно! респект! 

GarryC
Offline
Зарегистрирован: 08.08.2016

Хотите странного ? Пожалуйста ...

typedef struct {
    int array[2];
} array_t;
array_t func(int i1, int i2) {
    array_t tmp={i1,i2};
    return tmp;
};
#define ARRAY(a,b) func(a,b).array

void f2(int[2]) {
};
void f3(void) {
f2(func(1,2).array);
f2(ARRAY(1,2));
};