LINUX.ORG.RU

Альтернатива initializer_list в Си

 ,


0

2

Есть задача - инициализировать массив структур:

typedef struct { const double *inputs, *outputs; } Example;

где inputs и outputs - указатели на массивы даблов, произвольной длины, терминированные NaN.

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

Пока что пришел к такому варианту:

#include <stdio.h>
#include <math.h>

#define INIT_LIST(type, ...) ((const type[]){__VA_ARGS__})
#define DOUBLES(...) INIT_LIST(double, __VA_ARGS__, (double)NAN)
#define INIT_STRUCT_PTR(type, ...) (&(type){__VA_ARGS__})
#define EXAMPLE(...) INIT_STRUCT_PTR(Example, __VA_ARGS__)

typedef struct { const double *inputs, *outputs; } Example;

// NAN-terminated array of doubles
void printDoubles(const char *fmt, const double *nandedArray) {
    while(!isnan(*nandedArray)) {
        printf(fmt, *nandedArray++); // не секурно, зато удобно
    }
}

#define TAB "  "

// NULL-terminated array of examples
void printExamples(Example **examples) {
    for( ; *examples; ++examples) {
        printf("Example {\n" TAB "inputs {\n");
        printDoubles(TAB TAB "%f\n", (*examples)->inputs);
        printf(TAB "}\n" TAB "outputs {\n");
        printDoubles(TAB TAB "%f\n", (*examples)->outputs);
        printf(TAB "}\n}\n");
    }
}

int main() {
    Example *examples[] = {
        EXAMPLE(DOUBLES(1.23), DOUBLES(4.56, 7.89)),
        EXAMPLE(DOUBLES(10.11, 12.13), DOUBLES(14.15)),
        NULL
    };
    printExamples(examples);
}
Example {
  inputs {
    1.230000
  }
  outputs {
    4.560000
    7.890000
  }
}
Example {
  inputs {
    10.110000
    12.130000
  }
  outputs {
    14.150000
  }
}

В плюсовом коде я бы запилил вектор векторов и инициализировал бы его через initializer_list. Поэтому, оказавшись без столь удобных инструментов, я немного впал в ступор.

Какие есть еще варианты?

как-то так:

#include <stdio.h>
typedef struct FuckingDouble {
	double *one;
	double *two;
} FD;

FD fd[]={
	{ (double[]){1.0,2,3}, (double[]){4.0,5,6} },
	{ (double[]){7.0,8,9}, (double[]){10.0,11,12} }
};
int main() {
	printf("sizeof(fd)=%d",sizeof(fd));	
}
терминаторы добавить по вкусу :-) NaN на эту роль не годиться ну никак..

вектор даблов с терминатором, это тот ещё изват. в 99.99% размеры векторов и матриц известны. Да и их проще/быстрее проставить при IO чем внедрять в функции.

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

NaN на эту роль не годиться ну никак..

а на что годится NaN? вполне обычная пракика

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

в 99.99% размеры векторов и матриц известны.

Тем более, что в ТС-ном коде они вообще константны.

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

в 99.99% размеры векторов и матриц известны

Размерность списка инициализации в 100% случаев известна на этапе компиляции. Вопрос в другом - в удобстве инициализации структур, которые предназначены для хранения векторов произвольной длины. Датасеты считываются в рантайме из файлов/сети/бд, соответственно и размерность может быть абсолютно любой и определяется в рантайме. Списки инициализации понадобились для удобного и элегантного способа определения небольших датасетов без изменения типа данных и, соответственно, без изменения интерфейсов с ним работающих.

Хотелось бы увидеть минимально работающий код к предложенному вами решением, где структуры и их размеры передаются в функцию, при этом размерность векторов у каждого Example своя. Предложенный мною вариант именно так и работает, но мне хотелось бы посмотреть на альтернативные способы решения данной задачи.

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

Вопрос в другом - в удобстве инициализации структур

Си это не про удобство. Си это про закат солнца вручную. Если понадобилось удобство, то пора валить на что-то другое.

ox55ff ★★★ ()

Минусы:

1) Нет совместимости с C++

2) В чём проблема проверять fmt? Лень?

error: format not a string literal, argument types not checked [-Werror=format-nonliteral]
         printf(fmt, *nandedArray++);

fsb4000 ★★★ ()

Сишка - это труъ говорили они, руст не нужен говорили они...

Deleted ()

#define TAB " "

В голосяндру!

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

что-то имеешь против пробелов? может ты еще табами код форматируешь?

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

Написать свой CPP ... С блэкджеком и шлюхами.

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

может ты еще табами код форматируешь?

А ты что, отступы пробелами делаешь? А потом вносишь предложения вида «давайте вместо 4-ёх использовать 2, а то строки уезжают сильно», да ?-)

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

Я сразу использую два, а что не так. Это в code convention у многих проектов, например, llvm.

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

А чем ещё его форматировать? Не пробелами же. Пробелы нужны для промежутков между словами.

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

я вот форматирую clang-format'ом, мне вообще по барабану — табы, пробелы, сколько их там.

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

Не всем нравится отступ в два знака, а с табами привязки нет

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

в 2018 году кто-то сознательно неосторожно поднимает тему табы vs. пробелы

ну-ну)

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

в 2018 году кто-то сознательно неосторожно поддерживает и/или обращает внимание на тему табы vs. пробелы

Так-то лучше!

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

Я не мог пройти мимо, когда увидел, что кто-то до сих пор не понимает, что 4 пробела для индентации — золотой и бесспорный стандарт де-факто.

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

Зачем тогда столько сарказма в первом высказывании ?-) А по теме - можем поговорить на тему пруфов в области (не)стандартов )

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

Especially when you've been looking at your screen for 20 straight hours, you'll find it a lot easier to see how the indentation works if you have large indentations.

Шведофинну не рассказывали, что продуктивно умственно работать можно не более 5 часов в сутки?

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

Это зависит от определения понятия «продуктивность», да и ссылка не о том же была

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

Интересно, как бы матюкался Линус, если б ему понадобилось написать код с десятью уровнями вложенности. На 8-пробельных-то отступах!!!

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

Это зависит от определения понятия «продуктивность»

Можешь посмотреть в словаре, что означает слово «продуктивность», это ведь не какой-то технический термин с перегруженной смысловой нагрузкой.

ссылка не о том же была

А о чем была ссылка? О том, что в каком-то очень большом опенсорс проекте стиль кодирования предписывает 8 пробельный размер таба, причем оправдывается это охренительным примером, который я рассмотрел выше. И только.

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

А о чем была ссылка?

О том, что отступ в 4 пробела - не стандарт, даже де-факто. А обоснований на эту тему может быть два: гибкость или простота

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