[英]Casting pointer to struct to pointer to struct with const member
想象一下,您具有以下結構:
struct nix_codec {
nix_uint8 state;
nix_uint8 mode;
nix_uint8 flags;
nix_size offset;
nix_uint32 codepage;
nix_utf8 const *const *aliases;
void (*delete)(
struct nix_codec *codec,
struct nix_error *error
);
struct nix_codec* (*clone)(
struct nix_codec const *codec,
nix_int8 mode,
struct nix_error *error
);
nix_size (*decode)(
struct nix_codec *codec,
nix_byte const *bdata,
nix_size bsize,
nix_rune *udata,
nix_size usize,
struct nix_error *error
);
nix_size (*encode)(
struct nix_codec *codec,
nix_rune const *udata,
nix_size usize,
nix_byte *bdata,
nix_size bsize,
struct nix_error *error
);
};
typedef struct {
nix_uint8 const state;
nix_uint8 const mode;
nix_uint8 const flags;
nix_size const offset;
nix_uint32 const codepage;
nix_utf8 const *const *const aliases;
} nix_codec;
其中一個還具有幾個函數,這些函數用於創建nix_codec*
實例,例如,對於UTF-8編解碼器,它將看起來像這樣:
static nix_size self_decode
(
struct nix_codec *codec,
nix_byte const *bdata,
nix_size bsize,
nix_rune *udata,
nix_size usize,
struct nix_error *error
)
{ /* UTF-8 decode function, too long to post here */}
static nix_utf8 const *const aliases[] = {
"UTF-8",
"UTF8",
"CP65001",
NULL,
};
nix_codec *nix_codec_utf8
(
nix_int8 mode,
struct nix_error *error
)
{
struct nix_codec *codec = NULL;
if ((mode != NIX_CODEC_STRICT) && (mode != NIX_CODEC_ESCAPE)
&& (mode != NIX_CODEC_REPLACE) && (mode != NIX_CODEC_IGNORE)) {
return NULL;
}
codec = calloc(1, sizeof(struct nix_codec));
if (codec == NULL) {
return NULL;
}
codec->mode = mode;
codec->codepage = 65001;
codec->aliases = aliases;
codec->decode = &self_decode;
codec->encode = &self_encode;
codec->flags = (NIX_CODEC_COMPATIBLE | NIX_CODEC_MULTIBYTE | NIX_CODEC_ABSOLUTE);
return (nix_codec*)codec;
}
舊式單字節編碼的功能基於以下結構:
struct nix_sbmap {
nix_uint8 byte;
nix_rune rune;
};
struct nix_sbcodec {
struct nix_codec base;
struct nix_sbmap const *entries;
nix_size count;
};
注意, struct nix_sbcodec
和struct nix_sbmap
在源文件中聲明,而不是在頭文件中聲明,因此不需要使用variant
模式。 相應的函數,例如nix_codec_koi8r()
,分配一個struct nix_sbcodec
,設置其base
, entries
和count
成員,然后將其強制轉換為nix_codec
並返回它。 每一個實際的encode()
和decode()
使用這個公共職能進行呼叫:
nix_size nix_codec_decode
(
nix_codec *codec,
nix_byte const *bdata,
nix_size bsize,
nix_rune *udata,
nix_size usize,
struct nix_error *error
)
{
nix_size result = 0;
struct nix_codec *self = (struct nix_codec*)codec;
return self->decode(self, bdata, bsize, udata, usize, error);
}
請注意,對於使用任何編解碼器的任何人, state
, mode
, flags
和offset
成員可能都會感興趣(它們的大部分是在編解碼器創建函數中設置的, offset
在調用encode()
和decode()
函數之后更改,並表示在函數退出之前已成功處理的字節/ Unicode字符,如您所見,每個編解碼器都有其自己的encode()
和encode()
decode()
函數。
現在的問題是:這個技巧正確並且可以保證按C標准工作嗎?
提前致謝!
處理C中的變量類型(例如我認為您嘗試的方法)的一種可靠方法是使用union
。 例如:
typedef struct {
uint8_t x;
uint16_t y;
} obj_a;
typedef struct {
char *p;
char buf[42];
} obj_b;
typedef struct obj_base_s {
int (*internal_func)(struct obj_base_s *, int);
union {
obj_a a;
obj_b b;
} u;
} obj_base;
所有創建者/析構函數都將返回或使用obj_base
。 在union
中使用成員的函數可以直接訪問其位,也可以執行以下操作:
void handle_obja(obj_base *bp)
{
obj_a *oap = &bp->u.a;
oap->x = 23;
oap->y = 19;
...
}
C 不是 C ++,如果您想要漂亮的類,繼承,重載以及所有這些東西,請使用C ++。 這就是發明C ++的主要原因。 C不執行“類”。 C是一種底層語言。
請注意,使用任何編解碼器的任何人都可能對
state
,mode
,flags
和offset
成員感興趣(…現在的問題是:這個技巧正確並且可以保證按C標准工作嗎?
這種技巧 (不管是有用還是經常nix_codec
)都是不安全的,除非您斷言兩種結構類型的對應成員分別具有相同的偏移量,否則它是不安全的(通過指向不同定義的nix_codec
對象的指針來訪問struct nix_codec
對象的成員)在結構中; 對於獨立定義的結構類型,這不能保證; 此類保證僅存在於結構的並集內-請參見語言 / 表達式 / 后綴運算符 / 結構和並集成員 /第6段:
為了簡化並集的使用,做出了一項特殊保證:如果並集包含多個具有共同初始序列的結構(請參見下文),並且如果並集對象當前包含這些結構之一,則可以檢查該並集。可以看到任何已完成聯合類型聲明的地方的任何部分的初始部分。 如果相應的成員對一個或多個初始成員的序列具有兼容的類型(對於位域,則具有相同的寬度),則兩個結構共享一個公共的初始序列 。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.