C 结构体信息隐藏(不透明指针) [英] C struct information hiding (Opaque pointer)

查看:39
本文介绍了C 结构体信息隐藏(不透明指针)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前对 C 结构的信息隐藏概念有些困惑.

这个问题的背景是一个嵌入式 c 项目,对 OOP 的了解几乎为零.

到目前为止,我总是在相应模块的头文件中声明我的 typedef 结构.所以每个想要使用这个结构体的模块都知道结构体类型.

但经过 MISRA-C 检查后,我发现了中等严重性警告:MISRAC2012-Dir-4.8- 结构的实现不必要地暴露给翻译单元.

经过一番研究,我发现了 C 结构体信息隐藏的概念,将结构体成员的可见访问限制在私有范围内.

我立即尝试了一个简单的例子,它是这样的:

struct_test.h

//struct _structName;typedef struct _structName structType_t;

struct_test.c

#include "struct_test.h"typedef struct _structName{内部变量A;int varB;字符变量C;}structType_t;

main.c

#include "struct_test.h"structType_t myTest;myTest.varA = 0;myTest.varB = 1;myTest.varC = 'c';

这会产生编译器错误,即对于 main.c,myTest 的大小未知.当然,main.c 只知道存在 structType_t 类型的结构体,没有其他信息.

所以我继续我的研究并偶然发现了不透明指针的概念.

所以我尝试了第二次:

struct_test.h

typedef struct _structName *myStruct_t;

struct_test.c

#include "struct_test.h"typedef struct _structName{内部变量A;int varB;字符变量C;}structType_t;

main.c

#include "struct_test.h"myStruct_t myTest;myTest->varA = 1;

我得到编译器错误:解引用指向不完整类型struct _structName

的指针

很明显我还没有理解这种技术的基本概念.我的主要困惑点是 struct 对象的数据在哪里?

到目前为止,我的理解是,指针通常指向数据类型的物理"表示,并在相应地址上读取/写入内容.

但是使用上面的方法,我声明了一个指针 myTest 但从未设置它应该指向的地址.

我从这篇文章中得到了这个想法:什么是 C 中的不透明指针?

在帖子中提到,访问是通过 set/get 接口方法处理的,所以我尝试添加一个类似的方法:

void setVarA ( _structName *ptr, int valueA ){ptr->varA = valueA;}

但这也不起作用,因为现在他告诉我 _structName 是未知的...那么我是否只能在其他接口方法的帮助下访问结构,如果是,我如何在我的简单示例中实现这一点?

我更大的问题仍然是结构的对象在内存中的位置.我只知道指针的概念:

varA - 地址:10 - 值:1

ptrA - 地址:22 - 值:10

但在这个例子中我只有

myTest - 地址:xy - 值:??

我无法理解相应 myTest 指针的物理"表示位于何处?

此外,在我是模块的生产者和消费者的相对较小范围的嵌入式项目中,我看不到这样做的好处.

有人可以解释一下,这种方法对于 1-2 名开发人员使用代码的中小型嵌入式项目是否真的合理?目前,制作所有这些接口指针方法似乎比仅仅在我的头文件中声明结构更努力.

提前致谢

解决方案

正如您所推断的,当使用像这样的不透明类型时,主源文件无法访问结构的成员,实际上并没有不知道结构有多大.因此,您不仅需要访问器函数来读/写结构体的字段,还需要一个函数来为结构体分配内存,因为只有库源知道结构体的定义和大小.

因此您的头文件将包含以下内容:

typedef struct _structName structType_t;structType_t *init();void setVarA(structType_t *ptr, int valueA);int getVarA(structType_t *ptr);无效清理(structType_t *ptr);

这个接口允许用户创建结构体的实例,获取和设置值,并清理它.库源看起来像这样:

#include "struct_test.h";结构体名称{内部变量A;int varB;字符变量C;};structType_t *init(){返回 malloc(sizeof(structType_t));}void setVarA(structType_t *ptr, int valueA){ptr->varA = valueA;}int getVarA(structType_t *ptr){返回 ptr->varA;}无效清理(structType_t *ptr){免费(ptr);}

请注意,您只需定义一次 typedef.这既定义了类型别名,又向前声明了结构.然后在源文件中,实际的 struct 定义出现在没有 typedef 的情况下.

init 函数被调用者用来为结构分配空间并返回指向它的指针.然后可以将该指针传递给 getter/setter 函数.

所以现在你的主代码可以像这样使用这个接口:

#include "struct_test.h";int main(){structType_t *s = init();setVarA(s, 5);printf("s->a=%d\n", getVarA(s));清理;l}

I'm currently a bit confused regarding the concept of information hiding of C-structs.

The backround of this question is an embedded c project with nearly zero knowledge of OOP.

Up until now I always declared my typedef structs inside the header file of the corresponding module. So every module which wants to use this struct knows the struct type.

But after a MISRA-C check I discovered the medium severity warning: MISRAC2012-Dir-4.8 - The implementation of a structure is unnecessarily exposed to a translation unit.

After a bit of research I discovered the concept of information hiding of C-structs by limiting the visible access of the struct members to private scope.

I promptly tried a simple example which goes like this:

struct_test.h

//struct _structName;

typedef struct _structName structType_t;

struct_test.c

#include "struct_test.h"

typedef struct _structName
{
    int varA;
    int varB;
    char varC;
}structType_t;

main.c

#include "struct_test.h"

structType_t myTest;

myTest.varA = 0;
myTest.varB = 1;
myTest.varC = 'c';

This yields the compiler error, that for main.c the size of myTest is unknown. And of course it is, main.c has only knowledge that a struct of the type structType_t exists and nothing else.

So I continued my research and stumbled upon the concept of opaque pointers.

So I tried a second attempt:

struct_test.h

typedef struct _structName *myStruct_t;

struct_test.c

#include "struct_test.h"

typedef struct _structName
{
    int varA;
    int varB;
    char varC;
}structType_t;

main.c

#include "struct_test.h"

myStruct_t myTest;

myTest->varA = 1;

And I get the compiler error: dereferencing pointer to incomplete type struct _structName

So obviously I haven't understood the basic concept of this technique. My main point of confusion is where the data of the struct object will?

Up until now I had the understanding that a pointer usually points to a "physical" representation of the datatype and reads/writes the content on the corresponding address.

But with the method above, I declare a pointer myTest but never set an address where it should point to.

I took the idea from this post: What is an opaque pointer in C?

In the post it is mentioned, that the access is handled with set/get interface methods so I tried adding one similiar like this:

void setVarA ( _structName *ptr, int valueA )
{
  ptr->varA = valueA;
}

But this also doesn't work because now he tells me that _structName is unknown... So can I only access the struct with the help of additional interface methods and, if yes, how can I achieve this in my simple example?

And my bigger question still remains where the object of my struct is located in memory. I only know the pointer concept:

varA - Address: 10 - Value: 1

ptrA - Address: 22 - Value: 10

But in this example I only have

myTest - Address: xy - Value: ??

I have trouble understanding where the "physical" representation of the corresponding myTest pointer is located?

Furthermore I can not see the benefits of doing it like this in relatively small scope embedded projects where I am the producer and consumer of the modules.

Can someone explain me if this method is really reasonable for small to mid scale embedded projects with 1-2 developers working with the code? Currently it seems like more effort to make all this interface pointer methods than just declaring the struct in my header-file.

Thank you in advance

解决方案

As you've deduced, when using an opaque type such as this the main source file can't access the members of the struct, and in fact doesn't know how big the struct is. Because of this, not only do you need accessor functions to read/write the fields of the struct, but you also need a function to allocate memory for the struct, since only the library source knows the definition and size of the struct.

So your header file would contain the following:

typedef struct _structName structType_t;

structType_t *init();
void setVarA(structType_t *ptr, int valueA );
int getVarA(structType_t *ptr);
void cleanup(structType_t *ptr);

This interface allows a user to create an instance of the struct, get and set values, and clean it up. The library source would look like this:

#include "struct_test.h"

struct _structName
{
    int varA;
    int varB;
    char varC;
};

structType_t *init()
{
    return malloc(sizeof(structType_t ));
}

void setVarA(structType_t *ptr, int valueA )
{
    ptr->varA = valueA;
}

int getVarA(structType_t *ptr)
{
    return ptr->varA;
}

void cleanup(structType_t *ptr)
{
    free(ptr);
}

Note that you only need to define the typedef once. This both defines the type alias and forward declares the struct. Then in the source file the actual struct definition appears without the typedef.

The init function is used by the caller to allocate space for the struct and return a pointer to it. That pointer can then be passed to the getter / setter functions.

So now your main code can use this interface like this:

#include "struct_test.h"

int main()
{
    structType_t *s = init();
    setVarA(s, 5);
    printf("s->a=%d\n", getVarA(s));
    cleanup(s);l
}

这篇关于C 结构体信息隐藏(不透明指针)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆