簡體   English   中英

在 C 中用 char 數組初始化數字結構字段?

[英]Initialize numeric struct fields with char array in C?

假設我正在創建一個主要包含數字字段的結構。 然后,我想用 ASCII 字符的值初始化這些不同的字段,這樣最后,我可以將結構轉換為char*指針,並將其打印在一個 go 中,並獲得一種 per-結構的字節“映射”打印輸出。

我來到了以下編譯示例:

#include <stdio.h>
#include <string.h>
#include <inttypes.h>

struct mystruct_s {
  uint8_t id_tag[6]; 
  uint8_t fld_one[2];
  uint64_t fld_two;
  uint16_t fld_three;
  uint16_t fld_four;
  uint16_t fld_five;
};

struct mystruct_s myrh = {
  .id_tag = "123456",
  .fld_one = "78",
  .fld_two = (uint64_t) ((uint8_t[8]) { 'T', 'T', 'T', 'T', 'T', 'T', 'T', 'T' }),
};

int main() {
  printf("size %zu (%zu) bytes\n", sizeof(myrh), sizeof(struct mystruct_s));
  printf("as string:\n");
  printf("%s\n", (char*)&myrh);
  printf("char 10: '%c'\n", ((char*)&myrh)[9]);
  return 0;
}

...但是,當它運行時,它會產生:

$ gcc -g main.c -o main.exe
$ ./main.exe
size 24 (24) bytes
as string:
12345678`�V
char 10: ''

... 而我本來期望像12345678TTTTTTT這樣的東西(並且 char 10 也是'T')。 所以,很明顯我的“演員表”不太奏效。

那么,是否有某種語法,我可以在其中初始化一個結構的數字字段,其值相當於一個 char 數組? (請注意,上面的示例顯示了將所有字節 in.fld_two 初始化為“T”的意圖,即按照 ASCII 的 0x54 - 但我最終對指定這樣的具有不同字符的任意字符串感興趣)


第二件讓我感到驚訝的事情是,如果我添加另一個字段初始化:

...
struct mystruct_s myrh = {
  .id_tag = "123456",
  .fld_one = "78",
  .fld_two = (uint64_t) ((uint8_t[8]) { 'T', 'T', 'T', 'T', 'T', 'T', 'T', 'T' }),
  .fld_three = (uint16_t) ((uint8_t[2]) { 'E', 'E' }),
};
...

...然后構建失敗:

gcc -g main.c -o main.exe
main.c:18:16: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
   .fld_three = (uint16_t) ((uint8_t[2]) { 'E', 'E' }),
                ^
main.c:18:16: error: initializer element is not constant
main.c:18:16: note: (near initialization for ‘myrh.fld_three’)

那么,為什么它沒有檢測到這一行的錯誤:

.fld_two = (uint64_t) ((uint8_t[8]) { 'T', 'T', 'T', 'T', 'T', 'T', 'T', 'T' }),

...但它確實在這一行發現了一個錯誤:

 .fld_three = (uint16_t) ((uint8_t[2]) { 'E', 'E' }),

...即使兩條線顯然在做同樣的事情,只是大小和值不同?

(uint64_t) ((uint8_t[8]) { 'T', 'T', 'T', 'T', 'T', 'T', 'T', 'T' })

這會在與使用它的位置相同的 scope 處創建一個復合文字 與任何數組一樣, uint8_t [8]在表達式中使用時會衰減為指向第一個元素的指針。 所以你最終將地址轉換為uint64_t ,而不是數據。

您可以使用聯合類型雙關來解決這個問題。 就像是:

typedef union
{
  uint8_t  bytes [8];
  uint64_t u64;
} pun_intended;

...

.fld_two = (pun_intended){ .bytes = {'T', 'T', 'T', 'T', 'T', 'T', 'T', 'T'} }.u64,

然而,這帶來了另一個問題,即它不再是編譯時常量表達式。 當然,最好首先不使用草率的全局變量來解決這個問題。 但如果這不是一個選項(也許你需要const ),你可以選擇更改結構成員的類型:

pun_intended fld_two;
...
.fld_two = (pun_intended){ .bytes = {'T', 'T', 'T', 'T', 'T', 'T', 'T', 'T'} },

好吧,我設法通過聯合實現了我想要的效果——但是有太多的打字和樣板,它違背了目的(我想要 OP 中的語法,因為它看起來很簡單:))

#include <stdio.h>
#include <string.h>
#include <inttypes.h>

struct mystruct_s {
  uint8_t id_tag[6]; 
  uint8_t fld_one[2];
  uint64_t fld_two;
  uint16_t fld_three;
  uint16_t fld_four;
  uint16_t fld_five;
} __attribute__((packed));
struct mystruct_alt_s {
  unsigned char id_tag[6]; 
  unsigned char fld_one[2];
  unsigned char fld_two[8];
  unsigned char fld_three[2];
  unsigned char fld_four[2];
  unsigned char fld_five[2];
} __attribute__((packed));

union undata {
  struct mystruct_alt_s myo_alt;
  struct mystruct_s myo;
} ;

union undata data = {
  .myo_alt = {
    .id_tag = "123456",
    .fld_one = "78",
    .fld_two = "TTTTTTTT",
    .fld_three = "HH",
    .fld_four = "RR",
    .fld_five = "VV",
  }
};


int main() {
  printf("size %zu (%zu) bytes\n", sizeof(data), sizeof(struct mystruct_s));
  printf("as string:\n");
  printf("%s\n", (char*)&data.myo);
  return 0;
}

這打印:

$ gcc -g main.c -o main.exe
$ ./main.exe
size 22 (22) bytes
as string:
12345678TTTTTTTTHHRRVV

作為您自己的答案的替代方案,您可以使用新學習的 X 宏在一個地方收集變量定義和初始化字符串:

#include <stdio.h>
#include <string.h>
#include <inttypes.h>

// X macro taking Type, Name, Count, ValueString
#define FIELDS \
  X(uint8_t, id_tag, [6], "123456") \
  X(uint8_t, fld_one, [2], "78") \
  X(uint64_t, fld_two, , "TTTTTTTT") \
  X(uint16_t, fld_three, , "HH") \
  X(uint16_t, fld_four, , "RR") \
  X(uint16_t, fld_five, , "VV")

#define X(T,N,C,V) T N C;
struct mystruct_s {
  FIELDS
} __attribute__((packed));
#undef X

#define X(T,N,C,V) unsigned char N[sizeof(T C)];
struct mystruct_alt_s {
  FIELDS
} __attribute__((packed));
#undef X

union undata {
  struct mystruct_alt_s myo_alt;
  struct mystruct_s myo;
} ;

#define X(T,N,C,V) .N = V,
union undata data = {
  .myo_alt = {
    FIELDS
  }
};
#undef X

int main() {
  printf("size %zu (%zu) bytes\n", sizeof(data), sizeof(struct mystruct_s));
  printf("as string:\n");
  printf("%s\n", (char*)&data.myo);
  return 0;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM