Как стать автором
Обновить

Комментарии 37

НЛО прилетело и опубликовало эту надпись здесь
Что с форматированием? После одобрения модераторами все заголовки спойлеров попали под сам спойлер, а переносы строк в макросах пропали?
Например было так
#define function(x, ...) Generic((x),\
    int: function_int,\
   float: function_float,\
    char*: function_string)\
(PP_NARG(VA_ARGS) + 1, x, VA_ARGS)


А стало так
#define function(x, ...) Generic((x),    int: function_int,  float: function_float,  char*: function_string)(PP_NARG(VA_ARGS) + 1, x, VA_ARGS)


Это видимо не у меня одного так, я попытался с другого браузера открыть
НЛО прилетело и опубликовало эту надпись здесь

Это что значит (это просто мой первый пост)


Еще и нижние подчеркивания вокруг __VA_OPT__ и похожих слетели. Если кто из модераторов может починить, то я буду очень благодарен

НЛО прилетело и опубликовало эту надпись здесь

Привет, спасибо, разберёмся

Еще послетала подсветка языков. Это баг хабра?

Вы всё ещё можете редактировать свой пост.

Могу, но там очень много. И не факт что этот баг не повторится после модерации. Я надеюсь модераторы смогут починить

Вроде получается починить. Тогда сегодня может быть все почини (просто это будет долго)

Пока что прикреплю в начале статью png версию всего текста
Ура, я все починил. Если тут есть разработчики движка, то под спойлером в начале статьи я описал более-менее подробно особенности проблемы
Ленивый принтО — мой вариант для печати левой ногой.
printo(«текст», double, float, uint(8-32-64)_t, int(8-32-64)_t )
github.com/AVI-crak/Rtos_cortex/blob/master/sPrint.h
Всё тоже самое, только чуть проще и легче.

Хорошее альтернативное решение.


Но это конечно не тоже самое. В вашем решение вызываются для кажого аргумента отдельная функция, и нет собственно функции, которая принимает все аргументы. Хотя для большинства решения а тем более для print это может даже лучше


Еще заметил у вас do while(0), это как понимаю чтобы можно было использовать макрос в однострочных циклах и условиях. Учту это, а то у меня нигде это не использовалось

нет собственно функции, которая принимает все аргументы

Невозможно сделать такое на Си через одну функцию. Через макросы можно.
Но если используются макросы — то нет смысла в дополнительной программной обработке хитро сжатого пакета аргументов. Проще разложить по полочкам заранее.
Тем-более что выпрыгнуть с уровня макроса на уровень функции — очень и очень сложно. Там кода в сотни раз больше нужно чем у меня и вас.

Я имел ввиду что в моей функции реализации можно не просто выполнить по действию для разного аргумента, а можно сделать поведение относительно типов других аргументов.


Можно сказать что у меня это обычная variadic функция, которая дополнительно неявно получает количество своих аргументов и массив типов. У вас же можно сказать реализация функции уже записана в макросе, а в нем невозможно делать какие-то сложные операции


Повторюсь, у вас хороший макрос, сделанный проще и пограмотнее моего. Но все же это не одно и то же

Требование хотя бы одного параметра легко решается фиктивным параметром:


define println(...) cool_println("", VA_ARGS)

Разумеется более рационально ввести dummy тип и функцию печати для него, реализацию этого оставляю для вас.

Спасибо, пожалуй это отличное решение

Про dummy не понял вас. Что это за тип, и зачем функция печати для него

Ну смотрите, отличное решение всё равно заботит компилятор выводом строки на консоль. Казалось бы целых 0 байт в строке, но высока вероятность что этот вызов будет передан в libc и накладные расходы получаются уже более заметными.
Решение из мира С++ :


typedef struct {}please_dont_bother_printing_me;
please_dont_bother_printing_me please_dont_bother_printing_me_instance;
#define print(...) cool_print(please_dont_bother_printing_me_instance, __VA_ARGS__)

Я пока смотрел на ваш код у меня вопрос появился


x = &va_arg(argptr, int);

Почему так (и вообще как оно работает в этой вашей студии)?
Как я понимаю va_arg уже возвращает значение нужного типа (поэтому и получает его аргументом), поэтому у меня вопросы:
тут что, реально берётся указатель на стек?
зачем всё это если далее он снова кастится в нужный тип, почему не


printf("%d%s", va_arg(argptr, int), sep);

Или я что-то в СИ не понимаю?

Да, берется. Если это опасно, то могу исправить :) Я так сделал для наглядности, чтобы была отдельная переменная x

В Си я не эксперт, так что вам виднее. Это есть такое правило, что не в коем случае не стоит брать указатель на стек? Почему? Потому что если мы будем его использовать в другом блоке, то все поломается, или тут что-то большее? Просто в данном случае он используется более как локальный синоним. Логично, что потом я на этот указатель больше не ссылаюсь

О какой наглядности вообще речь, когда вы берёте int, получаете на него указатель, приводите к void*, преобразуете его макросом обратно в указатель на int, после чего в том же макросе разыменовываете указатель, превращая его снова в int?

Наглядность — дело субьективное. Для меня каст в воид и обратно кажется очень понятным

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

gcc это вообще не собирает, и он кстати прав
Дело в том, что строго говоря СИ функция обычно возвращает int не через стек а через регистр. Даже если оно вернулось через стек, не ясно какое у него время жизни, может статься что оно разрушается сразу же по присвоению. Я думаю тут дело вот в чем — вантузный компилятор превращает va_arg в вычисленную временную переменную, но это не верно т.к. в стандарте сказано что это функция (особенная). Вопрос времени жизни этой переменной открыт так что это UB

Спасибо большое за пояснение. Можете еще уточнить, это касается только указателей на аргументы, или любая запись вроде
int a = 5;
int* b = &a;
Будет ub? Ведь часто именно такие примеры есть при объяснении работы с указателями


И по каким запросам можно что-нибудь нашкглить про проблему указателей на стек? Бегло я ничего не смог найти

Тут все валидно, но нужно помнить что это указатель на переменную с конкретным временем жизни, если его использовать когда a уже уничтожено — опять таки UB.


ISO/IEC 9899:2011 6.2.4 §2, "The value of a pointer becomes indeterminate when the object it points to reaches the end of its lifetime."

Не получается, запятые все равно остаются
Вот так переопределил

#define cool_print(...)\
    cool_print_("", __VA_ARGS__)

#define cool_print_(...) \
	cool_print__(__VA_ARGS__ , COOL_RSEQ_N())


#define cool_print__(...) \
	COOL_ARG_N(__VA_ARGS__)


Вот такая ошибка:

image

Это мне напоминает другую ошибку, про которую я не написал, когда я в строку
cool_print_##n(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11,_12)
Первым аргументом поместил разделитель " ". Он каким-то образом «поднялся» вверх в самый верхний вложенный макрос

Я правда не знаю, это стандартизированная фишка макросов, или ошибка VS

Если интересует способ сравнить скорость с вариадиками и узнать насколько это будет быстрее в MSVC есть встроенный механизм для этого: https://devblogs.microsoft.com/cppblog/introducing-c-build-insights/


Последний MSVC должен поддерживать C17: https://devblogs.microsoft.com/cppblog/c11-and-c17-standard-support-arriving-in-msvc/

light_and_ray
Макросы работают снизу вверх: если что-то есть на второй строчке — то это что-то должно иметь описание на первой строке кода, при этом первая строка самодостаточна.
Дык вот и описание работы макросов нужно делать снизу вверх, иначе очень легко запутаться.
Нужно сначала посчитать количество аргументов, и написать макросы для всех количеств аргументов. И только потом узнавать тип аргумента, с подстановкой нужной функции.
На нулевое количество аргументов тоже есть место для макроса, есно на склейке с нулём.
Нужно сначала посчитать количество аргументов, и написать макросы для всех количеств аргументов. И только потом узнавать тип аргумента, с подстановкой нужной функции.

В моем решение если рассматривать макросы снизу вверх, то так и происходит

На нулевое количество аргументов тоже есть место для макроса, есно на склейке с нулём.

Проблема не в том, что cool_print_0 не определен. Проблема в том, что при подстановки ничего появляется ненужная запятая и синтаксическая ошибка
cool_print_(, 63, 62, 62, ...)
появляется ненужная запятая

Ну так я-же сказал — набор макросов для разных количеств аргументов. Там только имя макроса используется, а его аргумент можно (нужно) оставить пустым. Запятая потому и появляется, что несуществующий аргумент требует своего определения.
Я у себя проверил, с пустым аргументом вызывается нужная мне функция, без ошибок.
#define dpr_0() soft_print(" ")
Почему-то при записи _Generic(('a'), char: fun_char)() компилятор выдает что-то вроде «не найдена функция для int», так что на практике если передать символ в одинарных кавычках ничего не получится и он дай бог выведется как int
Не почему-то, а потому, что символ в одинарных кавычках в C, в отличии от C++, имеет тип int
Можете подсказать, как сделать оглавление в статье, чтобы оно еще и сбоку отображалось?

За что минус, тут нет никакой солидарности к людям, которые только зарегистрировались? Нормальный вопрос, так как в редакторе нигде нельзя выбрать оглавление. Поставил перед заголовками якори и они огде не отображаются


Гуглить пытался, в справке по форматированию не нашел. Что сразу минусить? Нормальный вопрос

Вы видели хоть у одного поста здесь подобным образом оформленное оглавление?


в справке по форматированию не нашел

Верный признак того, что такое оформление поста на Хабре невозможно.

Видел и не раз. Может это были технические статьи и я не разобрался


Конечно грубоватые тут некоторые люди в сообществое, которые так отвечают человеку, который только что присоединился. Я же это отдельным комментарием спросил, а не в самой статье, это даже не оффтоп

__VA_ARGS__ — это макрос. Он не делает никаких argument promotion по определению, это просто подстановка куска кода.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации