在 C 中是否有任何可能的方法(通过使用任何函数或任何此类函数)以便我们可以使用一行打印不同数据类型的结构中的内容? 比如说:
typedef struct ABC{
int a;
char b;
long c;
}ABC1;
要打印这个,我们需要写:
printf("%d %s %ld",ABC1.a,ABC1.b,ABC1.c)
任何其他方法,以便我可以像这样打印
printf("????",????ABC1)
??
首先,代码可能无法编译。您已将 ABC1 定义为 ABC 结构的 typedef。 ABC1不是变量,所以无法查看ABC1.a.的内容
假设您创建了一个类型为 ABC1 的变量,您不能使用 printf 以“逻辑”格式“转储”结构的内容。 printf 函数接收内存地址并根据给定的字符串显示其内容。如果 printf 函数只有一个指向内存的指针(即一堆字节,无法知道字节的“类型”),则它无法知道结构的格式。
没有。最好的解决方案是编写如下方法:
void printABC(struct ABC*)
或 char* abcToString(struct ABC*)
(然后通过%s
打印)。选项 2 可能更好,可用于写入文件等。
Glibc 允许您为
printf
和系列建立自己的格式说明符,以允许您通过一些扩展打印 UDT,否则这是不可能的。
#include <stdio.h>
#include <printf.h> /* For PA_POINTER */
struct MyStruct
{
int a;
double b;
};
struct print_info;
int handler(FILE *stream, const struct print_info *i,
const void* const *args)
{
const struct MyStruct *ptr = *( (const struct MyStruct**) (*args) );
int rc = fprintf(stream, "a: %d, b: %f\n", ptr->a, ptr->b);
return rc;
}
int print_arginfo (const struct printf_info *info, size_t n,
int *argtypes)
{
if (n > 0)
argtypes[0] = PA_POINTER;
return 1;
}
int main(void)
{
struct MyStruct s = {55, -3.14};
/* We're gonna use the M specifier */
int spec = 'M';
int rc = register_printf_function(spec, handler, print_arginfo);
if (rc != 0)
return 1;
printf("%M", &s);
};
您可以在这里找到文档。
printf()
仅支持预定义数据类型的格式说明符,不支持用户定义的数据类型(struct
)。而且,printf()
也没有办法自动learn你的struct
的成员变量的类型。
你需要滚动自己的函数来实现你想要的任务。
就像@john3136 说的。
但这是 1 的示例。
void printABC(ABC1 *ABC) /* can also use 'struct ABC*' */
{
printf("%d %c %ld",ABC->a,ABC->b,ABC->c);
/* Equivalent to the below */
/* printf("%d %s %ld",(*ABC).a,(*ABC).b,(*ABC).c); */
}
所以现在每次你想打印整个东西时,你只需输入类似
的内容 ABC1 xyz;
/* fill xyz here*/
printABC(&xyz);
并且它应该在一行中键入
ABC1
内的所有内容。
如果您使用的是现代 C 编译器,则可以使用泛型宏:
#include <stdio.h>
typedef struct {
int a;
char b;
long c;
} ABC;
// printf conversion specifiers:
#define CS(x) \
_Generic((x), \
int: "%d", \
char: "%c", \
long: "%ld")
int main (void)
{
ABC abc = {1, 'a', 2};
printf(CS(abc.a), abc.a); printf(" ");
printf(CS(abc.b), abc.b); printf(" ");
printf(CS(abc.c), abc.c); printf(" ");
return 0;
}
一种方法是为格式字符串和相应的参数定义宏:
#define ABCformat "%d,%c:%ld"
#define ABCarg(x) (x).a, (x).b, (x).c
并像这样使用它:
ABC1 abc = {1, 'c', 42};
printf("abc=" ABCformat "\n", ABCarg(abc));
您可以使用宏来描述结构,然后宏可以用来帮助创建结构定义和漂亮的打印机。
因此,您的代码可能如下所示:
PSTRUCT(ABC, (int, a), (char, b), (long, c));
int main () {
ABC abc = {1, 'a', 2};
printf("%s\n", tostring_ABC(&abc));
}
PSTRUCT
宏扩展为结构定义和遍历结构并将值发送到字符串中的函数。
#define PSTRUCT(N, ...) \
typedef struct { XX(PSTRUCT_ARG, __VA_ARGS__) } N; \
const char *tostring_##N (const N *x) { \
static _Thread_local char buf[512]; \
int len = 0; \
XX(PSTRUCT_ARG_PRINT, __VA_ARGS__) \
return buf; \
}
有辅助宏可以将各个字段正确扩展到结构定义中并打印字段值。
#define PSTRUCT_ARG(X) PSTRUCT_ARG2 X
#define PSTRUCT_ARG2(X, Y) X Y;
#define PSTRUCT_ARG_PRINT(X) PSTRUCT_ARG_PRINT2 X
#define PSTRUCT_ARG_PRINT2(X, Y) \
len += snprintf(buf+len, sizeof(buf)-len, CS(x->Y), #Y, x->Y);
CS
宏在Lundin 的回答中定义。迭代XX
宏定义为:
#define XX(X, ...) \
XX_X(__VA_ARGS__, XX_5, XX_4, XX_3, XX_2, XX_1) \
(X, __VA_ARGS__)
#define XX_X(_1,_2,_3,_4,_5,X,...) X
#define XX_1(X, _) X(_)
#define XX_2(X, _, ...) X(_) XX_1(X, __VA_ARGS__)
#define XX_3(X, _, ...) X(_) XX_2(X, __VA_ARGS__)
#define XX_4(X, _, ...) X(_) XX_3(X, __VA_ARGS__)
#define XX_5(X, _, ...) X(_) XX_4(X, __VA_ARGS__)
它是如何工作的在我的一个不同的答案中有简要描述。
为简单起见,忽略空结构情况。