一种结构,其成员有时需要为'const',有时不需要为'const'

一种结构,其成员有时需要为'const',有时不需要为'const',c,warnings,constants,C,Warnings,Constants,我正在开发一个程序,它在许多地方使用一个通用的struct,在相关的值之间穿梭。此结构包含一个字段char*s 许多函数修改s;但是,有时结构用于将信息传递给只读取信息的函数。在这些情况下,通常用于初始化s的字符串是const char*。但是,将其指定给s会导致编译器警告 虽然技术上正确,但此警告感觉是错误的,因为该函数不修改s。 除了扔掉常量之外,还有什么办法可以绕过这个警告吗?函数是否有办法保证将结构成员视为常量 例如: #include <stdio.h> struct m

我正在开发一个程序,它在许多地方使用一个通用的
struct
,在相关的值之间穿梭。此结构包含一个字段
char*s

许多函数修改
s
;但是,有时结构用于将信息传递给只读取信息的函数。在这些情况下,通常用于初始化
s
的字符串是
const char*
。但是,将其指定给
s
会导致编译器警告

虽然技术上正确,但此警告感觉是错误的,因为该函数不修改
s
。 除了扔掉常量之外,还有什么办法可以绕过这个警告吗?函数是否有办法保证将结构成员视为常量

例如:

#include <stdio.h>

struct mystruct{
  int i;
  char* s;
};

void i_only_read(const struct mystruct *m){
  printf("mystruct: i=%d, s=%s\n", m->i, m->s);
}

int main(int argc, char **argv){
  const char* cstr = "Hello";
  struct mystruct m;
  m.i=99;
  /* gcc warning: assignment discards ‘const’ qualifier
   * from pointer target type
   */
  m.s=cstr;
  i_only_read(&m);
}
#包括
结构mystruct{
int i;
char*s;
};
只读无效(const struct mystruct*m){
printf(“mystruct:i=%d,s=%s\n”,m->i,m->s);
}
int main(int argc,字符**argv){
const char*cstr=“你好”;
结构mystruct m;
m、 i=99;
/*gcc警告:分配丢弃“const”限定符
*从指针目标类型
*/
m、 s=cstr;
我只读(&m);
}
注释

  • 我无法将结构的声明更改为
    const char*s
    ,因为大多数指向结构的函数都会修改
    s
  • 我想我可以有两个结构,一个是
    char*s
    ,另一个是
    const char*s
    ,但这看起来非常难看(造成冗余,需要两个结构之间的转换函数)
  • 如果有人对程序感兴趣,那么结构就是
    struct attr
    。我为这个问题创建了一个简单的示例

  • 有趣的是,您似乎能够在
    联盟中做到这一点:

    struct mystruct {
        int i;
    
        union {
            char *s;
            const char *cs;
        };
    };
    
    现在,
    union
    的规则适用:仅使用分配给的union成员。如果函数“保证”正常运行,您可以将字符串分配给
    cs
    ,而无需发出警告


    具体地说,您不应该做的是分配给cs,然后将结构作为非常量参数传递。

    我意识到这个答案正是您的问题试图避免的。然而,如果不使用gcc以外的编译器或将代码扭曲成不可读性,那么有时一种严格的方法和代码中很少的注释就可以解决问题

    以下代码片段中的
    const
    的目的是什么

    void i_only_read(const struct mystruct *m){
      printf("mystruct: i=%d, s=%s\n", m->i, m->s);
    }
    
    从C的角度来看,这意味着该函数不会修改mystruct
    。如果该定义以某种方式给出了
    gcc
    fit,则删除
    const
    verbage并在代码中强制执行“不更新”透视图

    // the programmer can/must only read mystruct
    void i_only_read(struct mystruct *m){
      printf("mystruct: i=%d, s=%s\n", m->i, m->s);
    }
    

    这个解决方案有点复杂。它结合了@paddy对
    联合
    的建议,允许
    常量字符*
    赋值与另一个
    联合
    常量
    化版本的数据结构上,以提供严格的执行

    typedef struct const_mystruct {
        const int i;
        const char * const s;
    } const_mystruct;
    
    typedef union {
        struct {
            int i;
            union {
                char *s;
                const char *cs;
            };
        };
        const_mystruct cms;
    } mystruct;
    
    void i_only_read(const_mystruct *m){
      printf("mystruct: i=%d, s=%s\n", m->i, m->s);
    }
    
    int main(int argc, char **argv){
      const char* cstr = "Hello";
      mystruct m;
      m.i=99;
      m.cs=cstr;
      i_only_read(&m.cms);
    }
    

    基于paddy和jxh的想法,我提出了一个看起来很实用的解决方案:

    • 使用
      const char*
      成员创建结构的“const version”
    • 通过使用并集将其与结构的“非常量”版本组合
    代码:

    这实现了以下目标(类似于
    const
    限定符对简单指针的作用):

    • 函数可以接受const_mystruct*,如果它们希望保证不修改字符数组,编译器将强制执行此操作
    • mystruct
      适用于需要修改字符数组的情况/
      free()
      d
    • 最后,可以通过读取
      mystruct.cms
      mystruct
      转换为
      const\u mystruct
      。 通过写入
      mystruct.cms
      来转换
      const\u mystruct
      ->
      mystruct
      (潜在危险)是不可能的,因为
      mystruct.cms
      const
      ,因此不可写的
    说明使用的代码:

    #include <stdio.h>
    #include <malloc.h>
    /* [structs omitted] */
    
    void i_only_read(const const_mystruct *m){
      printf("mystruct: i=%d, s=%s\n", m->i, m->s);
    }
    
    void i_might_modify(mystruct *m){
      printf("noconst: mystruct: i=%d, s=%s\n", m->i, m->s);
    }
    
    int main(void){
      const char* cstr = "Hello";
      const_mystruct cm;
      cm.i=99;
      cm.s=cstr;
      // Method promises not to change the structure: OK.
      i_only_read(&cm);
      // Pass a "constant" structure into a method that might modify it:
      // diagnosed by compiler (warning or error).
      i_might_modify(&cm);
      // Trying to remove "const" from the pointer: compiler will not allow this...
      // m.cms.s=cstr; 
    
      mystruct m;
      m.i=99;
      m.s=malloc(10);
      // Struct is not "const", so modification is OK.
      i_might_modify(&m);
      // Convert to "const" struct, without cast.
      i_only_read(&(m.cms));
      return 0;
    }
    
    #包括
    #包括
    /*[省略结构]*/
    仅读无效(const const mystruct*m){
    printf(“mystruct:i=%d,s=%s\n”,m->i,m->s);
    }
    void i_may_modify(mystruct*m){
    printf(“noconst:mystruct:i=%d,s=%s\n”,m->i,m->s);
    }
    内部主(空){
    const char*cstr=“你好”;
    const_mystruct cm;
    cm.i=99;
    cm.s=cstr;
    //方法承诺不会更改结构:OK。
    i_only_read(&cm);
    //将“常量”结构传递给可能修改它的方法:
    //由编译器诊断(警告或错误)。
    i_可能会修改(&cm);
    //试图从指针中删除“const”:编译器将不允许此操作。。。
    //m.cms.s=cstr;
    我的结构;
    m、 i=99;
    m、 s=malloc(10);
    //Struct不是“const”,所以修改是可以的。
    我可以修改(&m);
    //转换为“const”结构,不使用强制转换。
    我只读(&(m.cms));
    返回0;
    }
    
    这提供了与使用
    const
    作为指针相同的保证,这是我的目标(类似于“递归const”)

    潜在问题:

    • 设置似乎相当复杂,其他开发人员可能很难理解它(我当然有)
    • 拥有相同结构的两个版本感觉很笨拙

    我将看看我是否能真正使用这个…

    +1我正在实现一个通用字符串对象,它可以通过复制或不复制进行初始化,我也遇到了这个问题。我很高兴你问这个问题。@H2CO3:啊,没关系:-S@KerrekSB没问题-如果从
    const char*
    (char*)
    的C样式转换也是安全的,我会很高兴地使用它:)当然,1。通过联合体的类型双关是安全的,2。同一类型的合格和不合格版本保证具有相同的表示和对齐要求,因此在初始化
    cs
    时读取
    s
    是安全的,反之亦然。谢谢@H2CO3。
    #include <stdio.h>
    #include <malloc.h>
    /* [structs omitted] */
    
    void i_only_read(const const_mystruct *m){
      printf("mystruct: i=%d, s=%s\n", m->i, m->s);
    }
    
    void i_might_modify(mystruct *m){
      printf("noconst: mystruct: i=%d, s=%s\n", m->i, m->s);
    }
    
    int main(void){
      const char* cstr = "Hello";
      const_mystruct cm;
      cm.i=99;
      cm.s=cstr;
      // Method promises not to change the structure: OK.
      i_only_read(&cm);
      // Pass a "constant" structure into a method that might modify it:
      // diagnosed by compiler (warning or error).
      i_might_modify(&cm);
      // Trying to remove "const" from the pointer: compiler will not allow this...
      // m.cms.s=cstr; 
    
      mystruct m;
      m.i=99;
      m.s=malloc(10);
      // Struct is not "const", so modification is OK.
      i_might_modify(&m);
      // Convert to "const" struct, without cast.
      i_only_read(&(m.cms));
      return 0;
    }