Подтвердить что ты не робот

Как я могу печатать значения в C без указания их типов, например, с помощью cerr << (A) << endl "в С++?

В С++, имея

#define DEBUG(A) cerr << (A) << endl;

Я могу отправить что-нибудь к нему, и он может его распечатать. Однако в C я должен указать его тип с% d,% c или% s и т.д. Но я не хочу писать его тип все время, я хочу использовать fprintf как cerr. Как я могу это сделать?

Например: в C

#define DEBUG(A) X // X is what I want to write 
...
// in function, when I put
DEBUG(5);          // I just want to print 5 
// or, with same statement, when I say 
DEBUG('a');        // output : a
4b9b3361

Ответ 1

Вы можете использовать Расширения языка GNU C:

#define DEBUG(x)                                                 \
  ({                                                             \
    if (__builtin_types_compatible_p (typeof (x), int))          \
        fprintf(stderr,"%d\n",x);                                \
    else if (__builtin_types_compatible_p (typeof (x), char))    \
        fprintf(stderr,"%c\n",x);                                \
    else if (__builtin_types_compatible_p (typeof (x), char[]))  \
        fprintf(stderr,"%s\n",x);                                \
    else                                                         \
        fprintf(stderr,"unknown type\n");                        \

  })

Это нормально:

DEBUG("hello"); //prints hello
DEBUG(11110);   //prints 11110 

Но для символов вы должны использовать его с lvalue, иначе его тип будет "int":

char c='A';
DEBUG(c);    // prints A
DEBUG('A');  // prints 65

Ответ 2

Вы не можете использовать fprintf() так, как хотите. Добро пожаловать в C.

Операторы потока ввода-вывода С++ являются типичными и используют перегрузку оператора для достижения своей магии. Это не доступно в C, поэтому вы должны придерживаться небезопасных подстрок строк.

Ответ 3

В принципе вы не можете, так как C не имеет механизма перегрузки.

Однако вы можете определить несколько макросов, например:

#define DEBUG_INT(x)  fprintf(stderr, "%d\n", (x))
#define DEBUG_CHAR(x) fprintf(stderr, "%c\n", (x))

Ответ 4

Невозможно избавиться от спецификаций преобразования, но если у вас есть компилятор C99, вы можете использовать __VA_ARGS__ и сделать его немного проще, например, в

#include <stdio.h>

#define DEBUG(fmt, ...) fprintf(stderr, (fmt), __VA_ARGS__)

int main(void) {
  int foo = 42;
  char *t = "foobar";
  DEBUG("%s:%d\n", t, foo);
  return 0;
}

Ответ 5

В C вы не можете надежно определить тип объекта. Следовательно, вам нужно будет ввести некоторый механизм поддержки общего программирования, например. охватывающий все объекты в структуре, которая содержит информацию о типе:

enum {type_int, type_double, type_string, /* ... */ } type_t;
struct {
        type_t type;
        void *obj;
} generic_type;

Теперь вы можете переключиться на ((generic_type)my_object).type. Вероятно, это не то, что вы ищете.




Однако есть простой трюк, чтобы определить, является ли аргумент макроса строковым литералом или чем-то еще. С символом макрокоманды '#' вы можете включить макрос в строку:

#define DEBUG(x) if (#x[0] == '"') printf("%s\n", x); else printf("%d\n", x)

Теперь вы можете сделать следующее:

DEBUG("foo bar");  // prints "foo bar"
DEBUG(23);         // prints "23"

В обратном направлении это не позволит вам различать, например, int и float s. Кроме того, указатели на char не распознаются как строки:

char *foo = "bar";
DEBUG(foo);        // prints the value of foo, not the string pointed to by foo

double salary;
DEBUG(salary);     // prints (int)salary, not (double)salary

На некоторых машинах sizeof(double) != sizeof(int). Это может помочь провести различие между различными типами аргументов макроса, но это, конечно, не переносимо.




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

Мой совет: просто привыкнете к форматированию спецификаторов.

Ответ 6

Вместо использования __VA_ARGS__ вы можете просто сделать следующее:

#define DEBUG(x...) fprintf(stderr, x)

В отличие от встроенных методов GCC, этот метод позволяет вам смешивать и сопоставлять - вы можете печатать "string =" вместо одного типа за раз. Вы также не столкнетесь с несовместимостью по размеру и типу - это по сути то же самое, что и fprintf, кроме возможности быть исключенным во время сборки!