简体   繁体   English

将指针转换为具有const成员的结构指针

[英]Casting pointer to struct to pointer to struct with const member

Imagine that you have such structs: 想象一下,您具有以下结构:

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;

One has also several functions, which are used to create the nix_codec* instances, eg for UTF-8 codec it will look like this: 其中一个还具有几个函数,这些函数用于创建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;
}

The function for legacy single-byte encodings is based on such structures: 旧式单字节编码的功能基于以下结构:

struct nix_sbmap {
    nix_uint8 byte;
    nix_rune rune;
};

struct nix_sbcodec {
    struct nix_codec base;
    struct nix_sbmap const *entries;
    nix_size count;
};

Note that struct nix_sbcodec and struct nix_sbmap are declared in the source files, not in headers, thus there is no need to use variant pattern. 注意, struct nix_sbcodecstruct nix_sbmap在源文件中声明,而不是在头文件中声明,因此不需要使用variant模式。 The corresponding function, eg nix_codec_koi8r() , allocates a struct nix_sbcodec , sets its base , entries and count members and then casts it to nix_codec and returns it. 相应的函数,例如nix_codec_koi8r() ,分配一个struct nix_sbcodec ,设置其baseentriescount成员,然后将其强制转换为nix_codec并返回它。 Every actual encode() and decode() calls are performed using this public function: 每一个实际的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);
}

Note that state , mode , flags and offset members may be interesting to anyone using any codec (the most part of them is set in codec creator functions, offset is changed after calls to encode() and decode() functions and represents the count of bytes/Unicode characters which were successfully processed before function exited. Each codec has its own encode() and decode() functions as you see. 请注意,对于使用任何编解码器的任何人, statemodeflagsoffset成员可能都会感兴趣(它们的大部分是在编解码器创建函数中设置的, offset在调用encode()decode()函数之后更改,并表示在函数退出之前已成功处理的字节/ Unicode字符,如您所见,每个编解码器都有其自己的encode()encode() decode()函数。

Now the question: is this trick correct and guaranteed to work by the C Standard? 现在的问题是:这个技巧正确并且可以保证按C标准工作吗?

Thanks in advance! 提前致谢!

A reliable way of dealing with variant types in C, such as what I think you are attempting, is to use a union . 处理C中的变量类型(例如我认为您尝试的方法)的一种可靠方法是使用union For example: 例如:

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;

All the creator / destructor functions will return or use an obj_base . 所有创建者/析构函数都将返回或使用obj_base Functions that use members in the union can either access their bits directly else do something like this: union中使用成员的函数可以直接访问其位,也可以执行以下操作:

void handle_obja(obj_base *bp)
{
     obj_a *oap = &bp->u.a;
     oap->x = 23;
     oap->y = 19;
     ...
}

C is not C++, if you want nice classes, inheritance, overloading and all that stuff, then use C++. C 不是 C ++,如果您想要漂亮的类,继承,重载以及所有这些东西,请使用C ++。 That is the main reason why C++ was invented. 这就是发明C ++的主要原因。 C does not do "classes". C不执行“类”。 C is a much lower level language. C是一种底层语言。

Note that state , mode , flags and offset members may be interesting to anyone using any codec (… 请注意,使用任何编解码器的任何人都可能对statemodeflagsoffset成员感兴趣(…

Now the question: is this trick correct and guaranteed to work by the C Standard? 现在的问题是:这个技巧正确并且可以保证按C标准工作吗?

However useful it may be and however often it may work, this trick (accessing members of a struct nix_codec object by a pointer to a differently defined nix_codec object) is unsafe unless you assert that the corresponding members of both structure types have respectively the same offset in the structures; 这种技巧 (不管是有用还是经常nix_codec )都是不安全的,除非您断言两种结构类型的对应成员分别具有相同的偏移量,否则它是不安全的(通过指向不同定义的nix_codec对象的指针来访问struct nix_codec对象的成员)在结构中; this is not guaranteed for the independently defined structure types; 对于独立定义的结构类型,这不能保证; such guarantee exists only within a union of the structures - see section Language / Expressions / Postfix operators / Structure and union members / paragraph 6: 此类保证仅存在于结构的并集内-请参见语言 / 表达式 / 后缀运算符 / 结构和并集成员 /第6段:

One special guarantee is made in order to simplify the use of unions: if a union contains several structures that share a common initial sequence (see below), and if the union object currently contains one of these structures, it is permitted to inspect the common initial part of any of them anywhere that a declaration of the completed type of the union is visible. 为了简化并集的使用,做出了一项特殊保证:如果并集包含多个具有共同初始序列的结构(请参见下文),并且如果并集对象当前包含这些结构之一,则可以检查该并集。可以看到任何已完成联合类型声明的地方的任何部分的初始部分。 Two structures share a common initial sequence if corresponding members have compatible types (and, for bit-fields, the same widths) for a sequence of one or more initial members. 如果相应的成员对一个或多个初始成员的序列具有兼容的类型(对于位域,则具有相同的宽度),则两个结构共享一个公共的初始序列

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM