3

我正在开发一个程序,该程序struct在许多地方使用泛型来遍历相关值。该结构包含一个字段char* s

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

虽然在技术上是正确的,但这个警告感觉不对,因为函数没有修改s. 除了丢弃 const 之外,有没有办法绕过这个警告?函数是否有某种方式可以保证它将结构成员视为const

例子:

#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);
}

笔记

  1. 我无法将 struct 的声明更改为const char* s,因为大多数采用指向 struct 的指针的函数都会修改s
  2. 我想我可以有两个结构,一个 withchar* s和一个 with const char* s,但这看起来很丑陋(创建冗余,需要两个结构之间的转换函数)。
  3. 如果有人对该程序感兴趣Navit,则结构是struct attr. 我为这个问题创建了一个简单的例子。
4

4 回答 4

5

有趣的是,您似乎可以在 a 中执行此操作union

struct mystruct {
    int i;

    union {
        char *s;
        const char *cs;
    };
};

现在,应用规则union:仅使用分配给的工会成员。如果函数“承诺”表现,您可以将字符串分配给cs而不发出警告。

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

于 2013-08-05T22:12:57.180 回答
2

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

  • const char*使用成员创建结构的“常量版本”
  • 通过使用联合将它与结构的“非常量”版本结合起来

代码:

typedef struct const_mystruct {
    int i;
    const char * s;
} const_mystruct;

typedef union {
    struct {
        int i;
        char *s;
    };
    const const_mystruct cms;
} mystruct;

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

  • 如果函数const_mystruct*想要承诺不修改 char 数组,则可以接受,编译器将强制执行此操作。
  • mystruct适用于确实需要修改 char 数组的情况free()
  • 最后, amystruct可以const_mystruct通过阅读转换为 a mystruct.cms。(潜在危险的)转换const_mystruct->mystruct通过写入mystruct.cms是不可能的,因为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,这是我的目标(有点像“递归常量”)。

潜在问题:

  • 设置看起来相当复杂,其他开发人员可能很难理解它(我当然有)。
  • 有两个相同的版本感觉很笨拙struct

我看看能不能用这个。。。

于 2013-08-07T22:56:21.880 回答
1

这个解决方案有点复杂。它结合了@paddy 的建议,union允许在数据结构的 -ified 版本上const char *与另一个分配,以提供严格的执行。unionconst

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);
}
于 2013-08-06T01:46:53.680 回答
0

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

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

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

从 C 的角度来看,这意味着该函数不会修改mystruct. 如果以某种方式这个定义很gcc合适,那么删除const措辞并在代码中强制执行“不更新”透视图。

// 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);
}
于 2013-08-05T23:10:31.343 回答