以多个结构打印数据

时间:2017-06-09 19:08:45

标签: c file struct

我正在处理四种不同的结构,其中两种非常大。我有一个函数将每个结构的每个值写入.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个值) 有更简单的方法吗?如果是这样,我该怎么做?

3 个答案:

答案 0 :(得分:2)

以下解决方案定义了一个union,它将实际的struct与其整数成员组合在一起,形成一系列整数值,以便"查看" struct members作为可通过订阅访问的数组元素。

要进行此保存,我们需要控制对齐,因为编译器可能会在数据成员之间添加填充。然后,这将使" array-view"指向无效的内存并引入未定义的行为。

我建议使用#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;
}

答案 1 :(得分:1)

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

这样的事情:

#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;
}

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

答案 2 :(得分:1)

通过int访问struct数组,反之亦然,如果这个答案可能有效,可能不会。然而,我现在对它与一般类型的使用并不那么有信心。将此保留为任何人添加/修改/删除的维基。

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);