【问题标题】:Cast between struct pointer in C在C中的结构指针之间转换
【发布时间】:2012-12-03 14:58:52
【问题描述】:

请考虑以下代码。

typedef struct{
    int field_1;
    int field_2;
    int field_3;
    int field_4;

    uint8_t* data;
    uint32_t data_size;
} my_struct;

void ext_function(inalterable_my_struct* ims, ...);

我想允许ext_function(由第三方编写)仅修改my_struct 中的field_3field_4。所以我做了以下事情:

typedef struct{
    const int field_1;
    const int field_2;
    int field_3;
    int field_4;

    const uint8_t* data;
    const uint32_t data_size;
} inalterable_my_struct;

void ext_function(inalterable_my_struct* ims, ...);

在调用ext_function之前在my_structinalterable_my_struct之间进行指针转换是否安全(如下所示)?

void call_ext_function(my_struct* ms){
    inalterable_my_struct* ims = (inalterable_my_struct*)ms;
    ext_function(ims, ...);
}

【问题讨论】:

  • 如果不想ext_function修改data,则应声明为const uint8_t* const data;

标签: c casting


【解决方案1】:

我认为这不是一个好主意。

被调用的函数总是可以抛弃任何const:ness,并根据需要修改数据。

如果你可以控制调用点,最好创建一个副本并使用指向该副本的指针调用函数,然后将你关心的两个字段复制回来:

void call_ext_function(my_struct* ms)
{
    my_struct tmp = *ms;
    ext_function(&tmp, ...);
    ms->field_3 = tmp.field_3;
    ms->field_4 = tmp.field_4;
}

更干净,除非您每秒执行数千次,否则性能损失应该很小。

如果函数触及它,您可能也必须伪造基于指针的数据。

【讨论】:

    【解决方案2】:

    根据 C99 标准,两个 structs 不会有兼容的类型,即使它们的声明相同。从第 6.7.7.5 节:

    示例 2 声明后

    typedef struct s1 { int x; } t1, *tp1;
    typedef struct s2 { int x; } t2, *tp2;
    

    类型t1tp1指向的类型是兼容的。 t1 类型也兼容 struct s1 类型,但不兼容 struct s2t2 类型、tp2int 指向的类型。

    此外,具有不同限定符的两种类型不被认为是兼容的:

    为了使两个合格的类型兼容,两者都应具有相同的合格版本 兼容类型;说明符或限定符列表中类型限定符的顺序 不影响指定类型。

    更简洁的方法是完全隐藏您的struct,用一个不起眼的句柄(typedefvoid* 之上)替换它,并提供用于操作struct 元素的函数。这样您就可以完全控制 struct 的结构:您可以随意重命名其字段,根据需要尽可能多地更改布局,更改字段的基础类型,以及做其他事情当您的客户知道struct 的内部布局时,您通常会避免这种情况。

    【讨论】:

      【解决方案3】:

      我认为这不是一个好主意,因为很难跟踪结构是否已转换(尤其是在代码很大的情况下)。同样将其转换为 const 并不能保证以后不会将其转换为 non-const structure

      unwind 提供的解决方案是一个非常好的解决方案。另一种(更明显)的解决方案是将结构拆分为两个较小的部分。

      typedef struct{
          const int field_1;
          const int field_2;
          const uint8_t* data;
          const uint32_t data_size;
      } inalterable_my_struct;
      
      typedef struct{
          int field_3;
          int field_4;
      } my_struct;
      
      void ext_function(const inalterable_my_struct* const ims, my_struct* ms ...);
      

      我在上面的调用中也使指针保持不变,但这不是必需的。

      【讨论】:

        【解决方案4】:

        即使标准没有说明它,它也可能适用于大多数编译器。如果你真的需要的话,你甚至可以用工会做一些更便携的事情。除非它不会改变任何东西。

        这就是它不会改变任何东西的原因:

        $ cat foo.c
        struct foo {
            const int a;
            int b;
        };
        
        void
        foo(struct foo *foo)
        {
            foo->a = 1;
        }
        $ cc -c foo.c
        foo.c: In function ‘foo’:
        foo.c:9: error: assignment of read-only member ‘a’
        $ cc -Dconst= -c foo.c
        $ 
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多