指向const结构的指针,仍然可以修改成员吗?

Ram*_*man 16 c

我有一个结构,我想通过一些回调函数传递给一些外部c代码,他们在我的程序中注册.但是,我想将该结构作为只读方式传递.我担心的是他们仍然可以修改我在我传递的原始结构中指向的结构.用下面的小例子解释:

struct s1 {
    int a;
    int b;
};

struct s2 {
    int x;
    struct s1 *y;
};

void f(const struct s2 *o)
{
    //o->x=10; //error
    o->y->a=20; //no error
    o->y->b=30; //no error
}

int main()
{
    struct s1 o1 = {10, 20};
    struct s2 o2 = {30, &o1};
    f(&o2);
}
Run Code Online (Sandbox Code Playgroud)

那么,我如何改进我的代码设计,以便他们不能修改我通过的结构?

til*_*z0R 9

要正确处理这种情况,您只能使用前向声明来隐藏成员以及getter和setter函数.

关注下面的代码并检查:

  • struct s1只有前向声明,所以你可以在其中指向它struct s2.
  • 实际执行的struct s1mylib.c因此,所有成员只能到库中可见,而不是用户.
  • 实现getter和setter以设置/读取这些隐藏成员的值,因为只有您的库可以访问成员,使其完全对用户隐藏.
  • 这迫使他使用你的功能.

mylib.h:

#ifndef __MYLIB_H
#define __MYLIB_H

//Create forward declaration only
//Implementation is in .c file
struct s1;

//Create user structure
struct s2 {
  int x;
  struct s1* y;
};

int get_a_from_s1(struct s2* s);
void set_a_to_s1(struct s2* s, int a);

#endif /* __MYLIB_H */
Run Code Online (Sandbox Code Playgroud)

mylib.c:

#include "mylib.h"

//Now implement structure
struct s1 {
  int a, b;
};

//Make getter
int
get_a_from_s1(struct s2* s) {
  return s->y->a;
}

//Make setter
void
set_a_to_s1(struct s2* s, int a) {
  s->y->a = a;
}
Run Code Online (Sandbox Code Playgroud)

main.c中:

#include <stdio.h>
#include "mylib.h"

int main(void) {
  struct s2 s;
  int a;

  ....

  s.y->a = 5; //error

  //Set s1.a value from s2 structure
  set_a_to_s1(&s, 10); //OK

  //To view members of s1 inside s2, create member functions
  a = get_a_from_s1(&s); //OK

  printf("a: %d\r\n", a);

  return 0;
}
Run Code Online (Sandbox Code Playgroud)

当然,请确保->y没有NULL或您有未定义的行为.

  • 为了记录,头部中具有不完整类型的"struct s1"的这种设计模式称为_opaque type_或_opaque pointers_. (3认同)

mem*_*emo 5

您可以像这样更改第二个结构声明:

struct s2 {
    int x;
    struct s1 const *y;
};
Run Code Online (Sandbox Code Playgroud)

添加的const确保 y 是只读的。


Ser*_*sta 5

你不能.即使你传递了struct s2by值,你也会在函数中得到一个指向非const的指针struct s1,因为它是根据它的定义s2包含的内容.

一旦你有一个指向非const对象的指针,你就可以改变那个对象.我在这里的意思和其他答案的意思是,它不是一个语言问题 - 更确切地说,语言在这里对你没有任何意义 - 而是一个设计问题.如果由于任何原因不能接受struct s1可以f从那时改变,那么你必须找到一个不同的设计,你不会将非const指针传递给它,不管它是const结构的成员.这里一个简单的方法是传递个人成员:

void f(int x, const struct s1 *y) {
    y->a = 20;  // error
}
Run Code Online (Sandbox Code Playgroud)

它可能不是你所期望的,但它是我能说的最好的C语言.