【问题标题】:Printing the data in multiple structs在多个结构中打印数据
【发布时间】:2017-06-09 19:08:45
【问题描述】:

我正在使用四个不同的结构,其中两个非常大。我有一个函数可以将每个结构的每个值写入 .txt 文件,但代码非常长且健壮。我正在寻找一种打印出每个值而不必对每个值进行硬编码的方法,但是到目前为止我在研究中发现的所有内容都表明硬编码是唯一的方法,但我想我会先在这里检查一下彻底放弃。就目前而言,我的代码如下所示:

char text[416];
    snprintf(text, 416, 
        "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d", 
        epsy.VBUS_voltage_mV,
        epsy.temp_internal_degC,
        epsy.status,
        batty.Z_pos_Camera_Temperature,
        batty.Z_neg_Camera_Temperature,
        batty.Y_pos_Camera_Temperature,
        batty.Y_neg_Camera_Temperature,
        batty.X_pos_Camera_Temperature,
        batty.FPGA_Temp_1,
        batty.FPGA_Temp_2,
        batty.Rx_Hinge_Temperature,
        batty.Bat_1_Vbat,
        batty.Bat_1_Ichg,
        batty.Bat_1_Idch,
        batty.Bat_1_MCU_Temp,
        batty.Bat_1_Temp_Therm,
        batty.Bat_1_Status,
        batty.Bat_2_Vbat,
        batty.Bat_2_Ichg,
        batty.Bat_2_Idch,
        batty.Bat_2_MCU_Temp,

...它会持续一段时间。 (80 个值) 有没有更简单的方法来做到这一点?如果是这样,我该怎么做?

【问题讨论】:

  • 尝试使用memcpy
  • 我很想写一个简短的 python 脚本来读取相关的头文件并为你编写 c 代码。
  • 可以粘贴结构定义吗?
  • ...以及一些搜索和替换编辑。
  • @ConnorOlsen 我用have a way 来处理这样的事情,尽管我怀疑它比你想要的更复杂。示例GPrintf(GP(epsy.VBUS_voltage_mV), " " GP(epsy.temp_internal_degC), " ", GP(epsy.status), GP_eol);

标签: c file struct


【解决方案1】:

以下解决方案定义了一个 union,它将实际的 struct 与其整数成员与整数值数组相结合,以便将结构成员“查看”为可通过订阅访问的数组元素。

为了进行保存,我们需要控制对齐方式,因为编译器可能会在数据成员之间添加填充。这将使“数组视图”指向无效内存并引入未定义的行为。

我建议使用#pragma pack(n) 来控制对齐。请注意,如果没有这种对齐方式,代码也可以工作,但是如果在“积分块”之前或之后引入其他类型的数据成员,它可能会出现问题(这也需要偏移“数组视图”,但那是此处未显示)。

需要周围的联合来保证数组和结构实际上是正确对齐的;否则,从结构到数组的强制转换可能会引入未定义的行为。

我知道#pragma pack 是不可移植的,它会影响内存布局,可能还会影响速度。然而,它应该适用于大多数编译器,我认为需要它来控制对齐以避免 UB:

#pragma pack(4)     /* set alignment to 4 byte boundary */

#define nrOfMyPackedDataElements 3

union MyPackedData {

    struct {
        int32_t firstInt;
        int32_t secondInt;
        int32_t thirdInt;
    } data;

    int32_t array[nrOfMyPackedDataElements];
};

#pragma pack()      /* reset alignment to compiler default */

int main() {

    union MyPackedData data;
    data.data.firstInt = 10;
    data.data.secondInt = 20;
    data.data.thirdInt = 30;

    for (int i=0; i < nrOfMyPackedDataElements; i++) {
        printf("%d ",data.array[i]);
    }

    return 0;
}

【讨论】:

    【解决方案2】:

    在 C11 中,您可以使用未命名的结构和联合字段重写您的 structs。

    类似这样的:

    #include <stdio.h>
    
    struct dir_t
    {
        int pos;
        int neg;
    };
    
    struct cam_temp_t
    {
        dir_t x;
        dir_t y;
        dir_t z;
    };
    
    // it seems that you have only ints in your structure...
    #define TOTAL_N_INTS 8
    
    struct batty_t
    {
        union
        {
            int data_[TOTAL_N_INTS];  
            struct
            {
                struct cam_temp_t camera_temperature;
                int               fpga;  // you get it...
                int               bat;
            }
        };
    };
    
    int main(void)
    {
        struct batty_t example = {
            .camera_temperature = {
                .x = {3, 4},
                .y = {5, 6},
                .z = {7, 8}
            },
            .fpga = 1,
            .bat = 2
        };
    
        for (int i = 0; i < TOTAL_N_INTS; ++i )
        {
            printf("%4d", example.data_[i]);
        }
        return 0;
    }
    

    当然如果你有不同的类型,你应该使用不同的数组。

    【讨论】:

      【解决方案3】:

      通过struct 访问int 数组,反之亦然,如此答案可能有效,也可能无效。然而,我现在对它与一般类型的使用不太自信。将此保留为 wiki,供任何人添加/修改/删除。


      OP 后来评论说struct 成员并不都是int。哦,好吧。


      如果所有成员都是并且永远是int ...

      通过int 偏移量一次访问每个成员。

      一些未经测试的代码来说明这个想法:

      int print_int_struct(char *dest, size_t d_size, const void *st, size_t s_size) {
        if (s_size % sizeof(int) != 0) {
          return -1; // bad struct size
        }
        size_t n = s_size / sizeof(int);
        const char *delimiter = "";
        for (size_t i = 0; i < n; i++) {
          int d;
          memcpy(&d, st, sizeof d);
          st = (char*) st + sizeof(int);
          int len = snprintf(dest, d_size, "%s%d", delimiter, d);
          if (len < 0 || (size_t) len >= d_size) {
            return -1; // out of room
          }
          dest += len;
          d_size -= len;
          delimiter = " ";
        }
        return 0;
      }
      struct s1 {
        int VBUS_voltage_mV;
        int temp_internal_degC;
        int status;
        ...
      };
      
      struct s1 st = ...;
      char buf[1024];
      print_int_struct(buf, sizeof buf, &st, sizeof st);
      puts(buf);
      

      【讨论】:

      • 编译器会不会以与整数数组不同的方式布置具有连续整数的结构(数组可能不引入填充,结构可能)?
      • @StephanLechner 这是一个非常有道理的担忧,但我相信答案是否定的。即使可以说它适用于所有类型,而不仅仅是int。不过,我必须做一些工作才能引用它。 This implies a problem,但还没有那么权威。
      • 如果int 的大小与机器的字长(通常是这样)相同,那么完全由ints 组成的结构之间可能不会有填充......尽管严格来说说这取决于编译器。
      • @GovindParmar 它的那些 unicorn machines 可能会在 64 位边界上填充 32 位 int 成员,这可能会破坏事情。 IAC,解决 OP 的问题 1) 更多信息会有所帮助 2) IMO,根据 struct 编写打印功能还不错。
      猜你喜欢
      • 2014-07-10
      • 1970-01-01
      • 1970-01-01
      • 2016-11-21
      • 2017-11-06
      • 2011-07-18
      • 2012-08-24
      • 1970-01-01
      • 2015-08-28
      相关资源
      最近更新 更多