使用C在结构体中创建静态数据的好方法是什么?

xmq68pz9  于 2023-08-03  发布在  其他
关注(0)|答案(1)|浏览(71)

我有这些结构体

typedef struct DeviceState_s {
    uint32_t Function_Type;
    uint8_t Left_Trigger;//byte [1]#9 left analog trigger
    uint8_t Right_Trigger;//byte [2]#10 right analog trigger
    uint8_t Buttons_1;//byte [3]#11 1----XY(1/Z) ..X and Y are the bits representing the buttons state (1 for unpress 0 for press) the last bit is z if the controller supports it.
    uint8_t Buttons_2;//byte [4]#12 PR PL PD PU start A B (1/C)  PR=pad right same for the rest and the bit marked as one is c if the controller supports it.
    uint8_t Analog_a1;//byte [5]#13 useless in original controller
    uint8_t Analog_a2;//byte [6]#14 useless in original controller
    uint8_t Analog_Y;//byte [7]#15 joystick Y axis movement
    uint8_t Analog_X;//byte [8]#16 joystick X axis movement

} DeviceState;

typedef struct DeviceStatus_s {
    uint32_t Function; 
    uint32_t DeviceID[3]; 
    uint8_t AreaCode; //1
    uint8_t ConnectorDirection; //1
    char ProductName[30];
    char ProductLicense[60];
    uint16_t StandbyPower; //2
    uint16_t MaxPower;  //2
} DeviceStatus;

typedef struct Status_FPacket_s {
    PacketHeader Header; //4
    DeviceStatus Status //112
} Status_FPacket;
static Status_FPacket Status_Packet;

字符串
然后再让它们跳动。但是没有必要每次都填充状态,它总是相同的。我想也许有一个是这样的。

typedef struct Status_FPacket_s {
    PacketHeader Header; //4
    DeviceStatus Status //112
    = {
        .Function = FUNC_CONTROLLER,
        .DeviceID[0] = 0xffff06fe,
        .DeviceID[1] = 0x0000ffff,
        .DeviceID[2] = 0x00000000,
        .AreaCode = 0xff,
        .ConnectorDirection = 0,
        .ProductName =0,
        .ProductLicense  =0,
        .StandbyPower =  (430>>8) | (430<<8),
        .MaxPower =  (500>>8) | (500<<8),
    };

} Status_FPacket;


但那没用也许我需要用我自己的类型?
/添加AbeMonk的建议//

typedef struct DeviceStatus_s {
    uint32_t Function; 
    uint32_t DeviceID[3]; 
    uint8_t AreaCode; //1
    uint8_t ConnectorDirection; //1
    char ProductName[30];
    char ProductLicense[60];
    uint16_t StandbyPower; //2
    uint16_t MaxPower;  //2
} DeviceStatus;

static DeviceStatus  controllerStatus =
{
    .Function=FUNC_CONTROLLER,
    .DeviceID[0]= 0xffff06fe,
    .DeviceID[1]= 0x0000ffff,
    .DeviceID[2] = 0x00000000,
    .AreaCode = 0xff,
    .ConnectorDirection = 0,
    .ProductName = "....";
    .ProductLicense "....";
    .StandbyPower =  (430>>8) | (430<<8),
    .MaxPower =  (500>>8) | (500<<8),
};


那就晚点再做吧
Status_Packet.Status = controllerStatus;
我用来设置琴弦的东西是
strncpy(Status_Packet.Status.ProductName,“text here”,sizeof(Status_Packet.Status.ProductName));
不知道如何做到这一点没有strncpy。

dphi5xsq

dphi5xsq1#

C不是面向对象的语言。虽然C中的结构体可以用来对数据进行分组,但它们的功能并没有超出这一范围--换句话说,它们提供的功能和抽象级别远不及C++类。然而,这并不意味着不可能在C中实现或至少接近理论上的“静态”结构成员。使用指针和全局变量,可以实现类似的功能:
首先,你需要初始化一个全局变量:

DeviceStatus global_status
= {
    .Function = FUNC_CONTROLLER,
    .DeviceID[0] = 0xffff06fe,
    .DeviceID[1] = 0x0000ffff,
    .DeviceID[2] = 0x00000000,
    .AreaCode = 0xff,
    .ConnectorDirection = 0,
    .ProductName =0,
    .ProductLicense  =0,
    .StandbyPower =  (430>>8) | (430<<8),
    .MaxPower =  (500>>8) | (500<<8),
};

字符串
然后,在将包含此“静态”成员的结构实现中,您将声明一个指针。这意味着全局变量将不需要跨示例复制,并且如果被一个示例修改,则将为所有示例更改:

typedef struct Status_FPacket_s {
   PacketHeader Header;
   DeviceStatus* Status; 
} Status_FPacket;


当然,将地址存储在指针中会占用空间(尽管比按值复制要少得多)。然而,我想不出一种方法来避免这一点(至少没有更明显的解决方案,即在所有需要全局变量的情况下直接使用全局变量;但是,我假设如果它足够话,您已经这样做了)。
现在,你所需要做的就是创建一个“构造函数”(从某种意义上说,我们试图模拟类),每次初始化Status_FPacket对象时都会调用它:

Status_FPacket create_Status_FPacket() {
    Status_FPacket obj;
    obj.Status = &global_status;
    return obj;
}


然后当你想初始化Status_FPacket对象时:

Status_FPacket status_packet = create_Status_FPacket();

可能的微小修改

我知道全局变量被认为是不好的做法。有一种方法可以解决这个问题,虽然可能有我不知道的重复(我已经尝试过了,它似乎工作)。你可以在“constructor”函数中创建一个静态变量,如下所示:

Status_FPacket create_Status_FPacket() {
    static DeviceStatus global_status
    = {
       .Function = FUNC_CONTROLLER,
       .DeviceID[0] = 0xffff06fe,
       .DeviceID[1] = 0x0000ffff,
       .DeviceID[2] = 0x00000000,
       .AreaCode = 0xff,
       .ConnectorDirection = 0,
       .ProductName =0,
       .ProductLicense  =0,
       .StandbyPower =  (430>>8) | (430<<8),
       .MaxPower =  (500>>8) | (500<<8),
    };

    Status_FPacket obj;
    obj.Status = &global_status;
    return obj;
}


C中的Static function variables是特殊的--它们在所有的函数调用中都保留在内存中的位置,并在应用程序的整个生命周期中存在。这意味着静态global_status变量实际上 * 每次 * 调用“构造函数”时 * 都是同一个示例。

避免使用strcpy

至于使用strcpy,完全可以避免这种不必要的开销。我假设您不会在内部修改productNameproductLiscense的值。在这种情况下,你可以将它们声明为常量char指针而不是数组,如下所示:

typedef struct DeviceStatus_s {
   uint32_t Function; 
   uint32_t DeviceID[3]; 
   uint8_t AreaCode; 
   uint8_t ConnectorDirection; 
   const char* ProductName;
   const char* ProductLicense;
   uint16_t StandbyPower; 
   uint16_t MaxPower; 
} DeviceStatus;


你现在可以直接使用**=**将字符串赋值给它们,因为它们是常量。

相关问题