首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

C 語言結構體數組初始化:不可見字符(0x20,0x03)賦值正確姿勢

     編輯:程式設計綜合問答

問題場景


typedef struct {
    char classname[128];
    char name[32];
    unsigned int id;
    char X[128];  // 存儲不可見控制字符
    int X_len;
} class_t;

// 嘗試初始化多組數據
class_t Temp[] = {
    {"One", "OneName", 1, {0x20, 0x03, 0x04}, 3},
    // ... 更多
};

只有第一組正確,後續數據錯亂。

根因:字符數組初始化語法誤解

{0x20, 0x03, 0x04} 被編譯器視為 **字符串字面量初始化**,而非字節數組。C 語言中 char arr[] = {0x20, 0x03} 合法,但作為結構體成員初始化時,嵌套大括號語法易產生歧義,導致後續字段錯位。

正確方案三種

1. 靜態數組 + memcpy 運行時賦值(推薦)


// 定義原始字節數據(十六進制可讀)
static const unsigned char raw_data[][3] = {
    {0x20, 0x03, 0x04},
    {0x10, 0x02, 0xFF},
    // ...
};

class_t Temp[2];
for (int i = 0; i < 2; i++) {
    strcpy(Temp[i].classname, i==0 ? "One" : "Two");
    strcpy(Temp[i].name, i==0 ? "OneName" : "TwoName");
    Temp[i].id = i + 1;
    memcpy(Temp[i].X, raw_data[i], 3);
    Temp[i].X_len = 3;
}

2. 指定初始化器 (C99,最清晰)


class_t Temp[] = {
    [0] = { .classname = "One", .name = "OneName", .id = 1, .X = {0x20, 0x03, 0x04}, .X_len = 3 },
    [1] = { .classname = "Two", .name = "TwoName", .id = 2, .X = {0x10, 0x02, 0xFF}, .X_len = 3 },
};
// 注意:.X = {...} 仍可能有編譯器差異,建議方案1

3. 十六進制字符串字面量(僅限可打印字符)


// \xHH 表示單字節,但 0x03 是控制字符,不可用此法
// 適用場景:可打印 ASCII
char data[] = "\x48\x65\x6C\x6C\x6F"; // "Hello"

調試驗證代碼


void print_hex(const char* label, const unsigned char* buf, int len) {
    printf("%s: ", label);
    for (int i = 0; i < len; i++) printf("%02X ", buf[i]);
    printf("\n");
}

int main() {
    // 初始化後驗證
    print_hex("Temp[0].X", (unsigned char*)Temp[0].X, Temp[0].X_len);
    print_hex("Temp[1].X", (unsigned char*)Temp[1].X, Temp[1].X_len);
    return 0;
}

核心原則

  1. 分離數據與代碼:原始字節表獨立定義,運行時拷貝
  2. 避免嵌套大括號初始化字節數組:語義模糊,編譯器實現差異大
  3. 使用 memcpy/memmove 處理二進制數據:類型安全、無符號擴展問題
  4. 結構體對齊注意:#pragma pack(1) 或屬性控制對齊,確保跨平台一致

採用「靜態數據表 + 運行時 memcpy」模式,穩健解決結構體中二進制字段批量初始化問題。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved