我有一个结构,我想通过一些回调函数传递给一些外部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);
}
那么,如何改进我的代码设计,以使他们无法修改我通过的结构?
答案 0 :(得分:9)
要正确处理这种情况,您只能使用前向声明将成员与getter和setter函数一起隐藏。
关注下面的代码并检查:
struct s1
仅具有 forward声明,因此您可以在struct s2
中指向它。 struct s1
的实际实现位于mylib.c
中,因此所有成员仅对您的库可见,而对用户不可见。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 */
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;
}
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;
}
当然,请确保->y
不是NULL
或您的行为不确定。
答案 1 :(得分:5)
您不能。即使您按值传递struct s2
,您也将在函数中获得指向非const struct s1
的指针,这仅仅是因为s2
根据其定义包含了 。
一旦有了指向非const对象的指针,就可以更改该对象。我在这里的意思以及其他答案的意思是,这不是语言问题-更确切的说,这里的语言对您没有帮助-而是设计问题。如果出于某种原因不能将struct s1
更改为f
,那么您必须找到一个不向其传递非const指针的其他设计,无论它是const的成员结构与否。一种简单的方法是传递各个成员:
void f(int x, const struct s1 *y) {
y->a = 20; // error
}
可能不是您所期望的,但这是我能用C语言说的最好的话。
答案 2 :(得分:4)
您可以像这样更改第二个struct声明:
struct s2 {
int x;
struct s1 const *y;
};
添加的const
确保y为只读。
答案 3 :(得分:0)
我将编写另一个函数,该函数采用const结构s1 *来修改s1的值。
答案 4 :(得分:0)
在f()
中,const struct s2 *o
表示struct s2
指向o
时,其成员的值即x
和{{1} }无法更改。
对于y
,您没有修改o->y->a=20
的值。您只是使用该地址来修改y
所指向的结构的成员,而y
的值(即地址)保持不变。
所以这两行不会出错。
除非您可以将y
定义为
struct s2
在这种情况下,struct s2 {
int x;
const struct s1 *y;
};
是指向常量y
的指针。
查看spiral rule并访问cdecl网站。