簡體   English   中英

將指針轉換為具有const成員的結構指針

[英]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_sbcodecstruct nix_sbmap在源文件中聲明,而不是在頭文件中聲明,因此不需要使用variant模式。 相應的函數,例如nix_codec_koi8r() ,分配一個struct nix_sbcodec ,設置其baseentriescount成員,然后將其強制轉換為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);
}

請注意,對於使用任何編解碼器的任何人, statemodeflagsoffset成員可能都會感興趣(它們的大部分是在編解碼器創建函數中設置的, 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是一種底層語言。

請注意,使用任何編解碼器的任何人都可能對statemodeflagsoffset成員感興趣(…

現在的問題是:這個技巧正確並且可以保證按C標准工作嗎?

這種技巧 (不管是有用還是經常nix_codec )都是不安全的,除非您斷言兩種結構類型的對應成員分別具有相同的偏移量,否則它是不安全的(通過指向不同定義的nix_codec對象的指針來訪問struct nix_codec對象的成員)在結構中; 對於獨立定義的結構類型,這不能保證; 此類保證僅存在於結構的並集內-請參見語言 / 表達式 / 后綴運算符 / 結構和並集成員 /第6段:

為了簡化並集的使用,做出了一項特殊保證:如果並集包含多個具有共同初始序列的結構(請參見下文),並且如果並集對象當前包含這些結構之一,則可以檢查該並集。可以看到任何已完成聯合類型聲明的地方的任何部分的初始部分。 如果相應的成員對一個或多個初始成員的序列具有兼容的類型(對於位域,則具有相同的寬度),則兩個結構共享一個公共的初始序列

暫無
暫無

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

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