在C语言中打印结构体字段和值

38

我对打印结构字段很感兴趣。

Typedef struct
{
   UINT32 thread_id;
   BOOL   is_valid;
}T_THREAD;
在“C”语言中是否有一种打印结构体内容的方法,类似于 例如:print(T_THREAD),并且输出应该像这样
Contents of a structure T_THREAD are 
  thread_id
  is_valid

2
你想打印特定实例的值还是一般结构的布局?(虽然无论如何答案都是否定的,但你必须自己完成) - user45891
1
我想打印一般结构的布局。如果我向结构中添加更多字段,则我的printf应该能够打印新添加的字段。 - user3555115
这个问题的答案在某些情况下可能很有用:https://dev59.com/xdrws4cB2Jgan1znMIRW - nielsen
6个回答

31
你需要的是反射。Java和其他虚拟语言有反射机制,因此您可以打印出任何给定类的变量名和函数名。这是因为编译器会自动构建这些反射函数。
C语言没有反射机制,您必须手动完成所有操作。

9
关于你的结构,函数看起来会像这样...
// st_name is the name of the struct
void print(T_THREAD *st, const char *st_name)
{
    printf("Contents of structure %s are %lu, %d\n", st_name, st->thread_id, st->is_valid);
}

struct *st 应该改为 T_THREAD *st。如果你做出这个改变,那么显然 st_name 就不再必要了。 - Ingo Leonhardt
2
当我们不知道结构体的元素时,我们应该如何打印? - vineeshvs

7

不行,没有现成的标准方法可以实现你想要的。

但是,你可以编写自己的函数,该函数了解要打印的特定结构元素值,然后通过单个对该函数的调用,使用特定结构变量的实例即可打印出所有成员的所有值。类似这样:

T_THREAD var;

my_print(var);  //my_print() is the function you'll roll out

应该能够打印出值。

但请注意,这并不允许您以任何方式打印变量名称,只能打印“值”。


4

使用单个printf语句无法打印所有结构元素。在C语言中,您需要手动将它们全部打印出来。以下是创建两个结构成员并将它们打印出来的示例:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

typedef struct {
    char *name;
    int thread_id;
    bool is_valid;
}T_THREAD;

int
main(void) {
    T_THREAD T1 = {"T1", 123, 1};
    T_THREAD T2 = {"T2", 456, 0};

    printf("\nContents of a structure %s are:\n", T1.name);
    printf("thread_id: %d\n",T1.thread_id);
    printf("is_valid: %d\n", T1.is_valid);

    printf("\nContents of a structure %s are:\n", T2.name);
    printf("thread_id: %d\n",T2.thread_id);
    printf("is_valid: %d\n", T2.is_valid);

    return 0;
}

输出:

Contents of a structure T1 are:
thread_id: 123
is_valid: 1

Contents of a structure T2 are:
thread_id: 456
is_valid: 0

另外,您也可以创建一个函数来执行此操作:

int
main(void) {
    T_THREAD T1 = {"T1", 123, 1};
    T_THREAD T2 = {"T2", 456, 0};

    print_struct_elements(&T1);
    print_struct_elements(&T2);

    return 0;
}

void
print_struct_elements(T_THREAD *T) {
    printf("\nContents of a structure %s are:\n", T->name);
    printf("thread_id: %d\n",T->thread_id);
    printf("is_valid: %d\n", T->is_valid);
}

3
当然可以在一个printf调用中打印所有内容:printf("\n结构体%s的内容为:\n线程ID:%d\n是否有效:%d\n", T->name, T->thread_id, T->is_valid); - simon

2
我认为像GDB这样的调试器可以完成此任务,但这比printf要麻烦一些。
  1. 使用带有调试符号的C文件进行编译。 "gcc -o test -g test.c"
  2. 将可执行文件附加到GDB上。 "gdb test"
  3. 运行GDB到打印结构体所在的行。(例如https://visualgdb.com/gdbreference/commands/print
  4. 打印结构体。 "p structA"
假设我有以下代码:
78    typedef struct
79    {
80       int thread_id;
81       int is_valid;
82    }T_THREAD;
83
84    T_THREAD tThread = { 0 } ;

在GDB中打印结构体的格式如下。
gdb -o test -g test.c
gdb test
(gdb) break 85
(gdb) run
(gdb) p tThread
$1 = {thread_id = 0, is_valid = 0}

有很多关于GDB的在线教程。 这里有一个可以帮助你入门的教程。 https://condor.depaul.edu/glancast/373class/docs/gdb.html


1
一种实现这个的方法是使用x-macros。虽然与内置于语言中的反射相比不够美观,但使用宏确实会使代码有点难以阅读,但它非常直接明了。
#include <stdio.h>
#include <stdint.h>

#define HDR_STRUCT_FIELDS       \
  FLD(0, Field_1, uint32_t, 3)  \
  FLD(1, Field_2, uint16_t, 4)  \
  FLD(2, Field_3, uint8_t,  5)

#define FLD(idx, fld, dt, initVal)   dt fld;
typedef struct 
{
    HDR_STRUCT_FIELDS
} HdrData_t;
#undef FLD

#define FLD(idx, fld, dt, initVal)   .fld = initVal,
HdrData_t HeaderData = 
{
   HDR_STRUCT_FIELDS
};
#undef FLD


#define QUOTE(field)     #field
#define FLD(idx, fld, dt, initVal)   [idx] = QUOTE(fld),
const char* HeaderDataName[] = 
{
   HDR_STRUCT_FIELDS
};
#undef FLD


int main()
{   
    #define FLD(idx, fld, dt, initVal)   printf("%s = %d\n", HeaderDataName[idx], HeaderData.fld);
    HDR_STRUCT_FIELDS
    #undef FLD

    return (0);
}

另一种不太重要的字段排序方法是使用结构体和初始化结构体,具体如下。
#include <stdio.h>
#include <stdint.h>

#define HDR_STRUCT_FIELDS    \
  FLD(Field_1, uint32_t, 3)  \
  FLD(Field_2, uint16_t, 4)  \
  FLD(Field_3, uint8_t,  5)

#define FLD(fld, dt, initVal)   dt fld;
typedef struct
{
    HDR_STRUCT_FIELDS
} HdrData_t;
#undef FLD


#define FLD(fld, dt, initVal)   .fld = initVal,
HdrData_t HeaderData =
{
   HDR_STRUCT_FIELDS
};
#undef FLD


#define FLD(fld, dt, initVal)   const char *fld;
typedef struct
{
   HDR_STRUCT_FIELDS
} HdrDataFldString_t;
#undef FLD

#define STRINGIZE(field)        #field
#define FLD(fld, dt, initVal)   .fld = STRINGIZE(fld),
HdrDataFldString_t  HdrDataFldString =
{
   HDR_STRUCT_FIELDS
};
#undef FLD


int main()
{
    #define FLD(fld, dt, initVal)   printf("%s = %d\n", HdrDataFldString.fld, HeaderData.fld);
    HDR_STRUCT_FIELDS
    #undef FLD

    return (0);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接