[英]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.