_Общая функция длины завершается с ошибкой по умолчанию: sizeof(x)/sizeof((x)[0])

Проблема:

Недавно я узнал о _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 (но я не уверен, галлюцинирует он или нет), так что... есть идеи, почему это происходит? заранее спасибо за любую помощь.

Для справки, ChatGPT все галлюцинирует. Не доверяйте ему написание или понимание кода.

Dúthomhas 18.08.2024 14:55

@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 и некоторую точность.

chux - Reinstate Monica 18.08.2024 19:39
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
2
59
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

_Generic выбирает одно из перечисленных выражений. Все перечисленные элементы должны быть допустимыми выражениями. Если x не является массивом или указателем, x[0] не является допустимым выражением. _Generic не похожа на директиву препроцессора, которая может условно игнорировать некоторый код. Весь код в нем должен быть грамматически корректным.

Удивительный! В большинстве случаев мне это не кажется необходимым и делает эту функцию гораздо менее полезной.

chqrlie 18.08.2024 17:06

@chqrlie Почему это удивительно, если это делает эту функцию менее полезной? ржу не могу

Giorgos Xou 18.08.2024 17:44

@chqrlie ИМО, я бы хотел, чтобы _Generic использовал только первое совпадение, чтобы можно было использовать потенциальные несколько совпадений, такие как int, int32_t. Это будет соответствовать вашей цели.

chux - Reinstate Monica 18.08.2024 19:41

Другие вопросы по теме