Почему я получаю формат printf для определенного базового типа данных в макросе?

#c #macros

#c #макросы

Вопрос:

Как написать FORMAT_OF(type) , чтобы это было %d для int , %s для и т.д. char *

Есть ли макрос для получения формата для базовых типов данных?

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

1. Чего именно вы пытаетесь достичь? Вы должны знать типы данных объектов в вашей программе…

2. @sarnold , в моем случае type это также определяется макросом.

3. До C1X вам придется писать макросы, которые принимают a fmt вместе с переменной.

4. @Chris Lutz , что ты имеешь в виду? Можете ли вы опубликовать это в качестве ответа? Я могу согласиться с этим, поскольку я не могу принять еще не поддерживаемое решение c1x …

5. @new_perl — В принципе, вместо PRINT(x) printf(FORMAT_OF(x), (x)) того, чтобы писать PRINT(fmt, x) printf(fmt, x) . Это больше кода у вызывающего, но это то, с чем вы застряли до C1X. Сейчас это не очень полезно, но если вы опубликуете больше о том, что вы пытались сделать, я мог бы помочь вам больше.

Ответ №1:

ДА. Но он доступен только в C11.

 #define FORMAT_OF(x) _Generic((x), 
    int: "%d", 
    unsigned: "%u", 
    const char *: "%s", 
    void *: "%p")
  

Для типов вместо значений вы могли бы попробовать _Generic((type) 0, ... .

Ваш компилятор, вероятно, не поддерживает C11. В GCC 4.6 (но не 4.5!) включена некоторая поддержка C11 с -std=c1x помощью or -std=gnu1x , но я не думаю _Generic , что она пока поддерживается.

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

1. @ChrisLutz: Я прочитал статью, в которой утверждалось, что стандарт был принят с единодушной поддержкой в предпоследнем голосовании, что означает, что окончательное голосование пропущено. Я не могу вспомнить, где я читал статью, и я не смог найти информацию на странице рабочей группы. Я не думаю, что он еще опубликован как C11, но это будет.

2. Потрясающе. Теперь все, что нам нужно сделать, это подождать еще 10 лет, пока они не начнут писать новый черновик для компиляторов, чтобы поддерживать его… (Кроме того, разве это не должно быть просто char * вместо const char * ? Или будет _Generic знать, что мой char str[] = "This"; должен соответствовать a const char * ? Может _Generic использоваться для различения const типов и не const типов?)

3. _Generic Макрос проверяет только совместимость типов, поэтому const char * будет перехватывать оба. Учитывая, что C11 фактически делает необязательными некоторые из обязательных функций C99, а некоторые из новых функций сильно перекрываются с C 11, я с осторожным оптимизмом смотрю на получение поддержки C11 «относительно скоро», по крайней мере, в GCC и Clang. На мой взгляд, новые функции C11 кажутся намного проще в реализации, чем новые функции в C99.

4. Отрадно видеть, что GCC уже поддерживает некоторые функции из C1X. Было бы просто приятно видеть, что современная поддержка C будет более распространенной, поскольку поддержка C99 распространена по всей карте и существует уже долгое время.

Ответ №2:

Нет. В настоящее время стандартизированные версии C не поддерживают самоанализ типа такого рода.

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

1. C11 имеет _Generic выражение.

Ответ №3:

Ну, если вы хотите, чтобы макрос принимал только тип, вы могли бы:

 #define FORMAT_int "%d"
#define FORMAT_char "%c"
...
#define FORMAT(x) FORMAT_##x
  

и использовать FORMAT(int) позже; но

 int i;
FORMAT(i);
  

не будет работать и FORMAT(char*) тоже не будет работать.

Ответ №4:

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

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

1. Как вы могли бы написать функцию-оболочку без C ?

2. Как бы вы написали такую функцию (без использования C201X _Generic )?

3. Вы могли бы сделать это с ограниченным диапазоном типов (например float , / double / long double ), используя sizeof или какой-либо другой трюк, но в целом это не сработает.

4. sizeof ? Это не покажет разницу между an int и a char* в большинстве систем!

5. @Dave — Вот почему я сказал «с ограниченным набором типов». Среди прочего, это делает его непригодным для определения printf форматов.