Недавно я узнал о _Generic
. Пытаясь использовать его в качестве универсального макроса длины, я наткнулся на странную проблему. Хотя LENA(x)
работает отлично, общий LEN(x)
не скомпилируется, пока я не удалю default
.
#include <stdio.h>
#include <string.h>
#define LENA(x) sizeof(x)/sizeof((x)[0])
#define LEN(x) _Generic((x), \
int : snprintf(NULL, 0, "%d" , (x)), \
unsigned int : snprintf(NULL, 0, "%u" , (x)), \
long : snprintf(NULL, 0, "%ld" , (x)), \
unsigned long : snprintf(NULL, 0, "%lu" , (x)), \
long long : snprintf(NULL, 0, "%lld", (x)), \
unsigned long long : snprintf(NULL, 0, "%llu", (x)), \
float : snprintf(NULL, 0, "%f" , (x)), \
double : snprintf(NULL, 0, "%f" , (x)), \
long double : snprintf(NULL, 0, "%Lf" , (x)), \
default : sizeof((x))/sizeof((x)[0]) \
)
int main() {
int i = 12345;
unsigned long ul = 18446744073709551615UL;
double d = 3.14159;
char str[] = "Hello, World!";
int arr[] = {1, 2, 3, 4, 5, 6, 7};
printf("Length of int : %d\n", LEN(i)); // Output: 5
printf("Length of Ulong: %d\n", LEN(ul)); // Output: 20
printf("Length of array: %d\n", LENA(arr)); // Output: 7
//printf("Length of array: %d\n", LEN(arr));
//printf("Length of str: %d\n", LEN(str));
return 0;
}
(особенно /sizeof((x)[0]
-часть).
ERROR!
/tmp/21gk5WXdQu.c: In function 'main':
/tmp/21gk5WXdQu.c:15:46: error: subscripted value is neither array nor pointer nor vector
15 | default : sizeof(x)/sizeof((x)[0]) \
| ^
/tmp/21gk5WXdQu.c:25:37: note: in expansion of macro 'LEN'
25 | printf("Length of int : %d\n", LEN(i)); // Output: 5
| ^~~
ERROR!
/tmp/21gk5WXdQu.c:15:46: error: subscripted value is neither array nor pointer nor vector
15 | default : sizeof(x)/sizeof((x)[0]) \
| ^
/tmp/21gk5WXdQu.c:26:37: note: in expansion of macro 'LEN'
26 | printf("Length of Ulong: %d\n", LEN(ul)); // Output: 20
| ^~~
Это ошибка или особенность? Я искал об этом, пробовал разные версии gcc, множество трюков, я даже спросил чатGPT (но я не уверен, галлюцинирует он или нет), так что... есть идеи, почему это происходит? заранее спасибо за любую помощь.
@Giorgos Xou, в сторону: для обычной печати FP рассмотрите snprintf(NULL, 0, "%.*g" , FLT_DECIMAL_DIG, (x))
, snprintf(NULL, 0, "%.*g" , DBL_DECIMAL_DIG, (x))
, snprintf(NULL, 0, "%.*Lg" , LDBL_DECIMAL_DIG, (x))
. Лучше использовать %g
и некоторую точность.
_Generic
выбирает одно из перечисленных выражений. Все перечисленные элементы должны быть допустимыми выражениями. Если x
не является массивом или указателем, x[0]
не является допустимым выражением. _Generic
не похожа на директиву препроцессора, которая может условно игнорировать некоторый код. Весь код в нем должен быть грамматически корректным.
Удивительный! В большинстве случаев мне это не кажется необходимым и делает эту функцию гораздо менее полезной.
@chqrlie Почему это удивительно, если это делает эту функцию менее полезной? ржу не могу
@chqrlie ИМО, я бы хотел, чтобы _Generic
использовал только первое совпадение, чтобы можно было использовать потенциальные несколько совпадений, такие как int
, int32_t
. Это будет соответствовать вашей цели.
Для справки, ChatGPT все галлюцинирует. Не доверяйте ему написание или понимание кода.