C 如何使结构成员私有?
我在头文件中定义了如下结构:C 如何使结构成员私有?,c,struct,C,Struct,我在头文件中定义了如下结构: typedef struct { void *data; } point; 我想防止其他人直接访问*数据,所以我想我应该在.c文件中声明结构,并使用类似于extern typedef struct point的东西。然而,这不起作用 实现这一点的最佳方法是什么?这是指向实现的指针或pimpl习惯用法。请参阅C++教程,但是这个想法也应该在C中工作。 < P>在您的(公共)头文件: typedef struct point point; 在.c文件中: s
typedef struct {
void *data;
} point;
我想防止其他人直接访问*数据,所以我想我应该在.c文件中声明结构,并使用类似于extern typedef struct point的东西头文件中的代码>。然而,这不起作用
实现这一点的最佳方法是什么?这是指向实现的指针或pimpl习惯用法。请参阅C++教程,但是这个想法也应该在C中工作。 < P>在您的(公共)头文件:
typedef struct point point;
在.c
文件中:
struct point
{
void *data;
};
请注意,代码的用户将不再能够在堆栈上创建点
,因为编译器不知道它有多大。您可能需要提供一个< C++ > PooToSKEATE()/<代码>函数,它分配内存并将其地址返回给调用方。
因为笑话似乎是不允许的,所以这里是纯C版本。
正如另一位评论者所指出的,如果您真的想保护您的内部构件不受Api用户的攻击,那么您已经看到并使用了大量这样的Api。此API是例如Windows或Linux用户模式API。在那里,您将创建您永远无法访问的内核对象。处理内核对象的API使用一个名为handle的合成结构,它不仅仅是指向您自己对象的指针,而是指向内核存储了对象相关元数据的数组的索引。
您也可以在API中使用相同的思想。
例如,这里是一个C风格的公共Api:
// Public.h
#include <stdlib.h>
typedef enum
{
None = 0,
PointType = 1
} Types;
typedef int Handle;
Handle CreateType(Types type);
int DeleteType(Handle object);
void IncrementX(Handle point);
void PrintPoint(Handle point);
private.cpp中有一个超级秘密实现,其中存在句柄查找数组和一些助手方法:
// Private.C
#include "stdafx.h"
#include <stdlib.h>
#include <Windows.h> // for ZeroMemory
#include "Public.h"
typedef struct
{
LPVOID pData;
Types type;
Handle handle;
} HandleInfo;
typedef struct
{
int x;
int y;
} Point;
HandleInfo *pAllocated;
int HandleBuffer = 0xffff;
unsigned char bInit = 0;
HandleInfo *GetFreeHandle()
{
int i;
if( !bInit )
{
pAllocated = (HandleInfo *) malloc(sizeof(HandleInfo)*HandleBuffer);
bInit = 1;
ZeroMemory(pAllocated, sizeof(HandleInfo)*HandleBuffer);
}
for(i=0; i<HandleBuffer; i++)
{
HandleInfo *pInfo = (pAllocated+i);
if( 0 == pInfo->handle )
{
pInfo->handle = i+1;
return pInfo;
}
}
return NULL;
}
HandleInfo * GetHandleInfo(Handle h)
{
if( h <= 0 || h >= HandleBuffer-1)
{
return NULL;
}
return (pAllocated+h-1);
}
Handle CreateType(Types typeId)
{
HandleInfo *pInfo;
pInfo = GetFreeHandle();
if( NULL == pInfo )
{
return -1;
}
pInfo->type = typeId;
switch(typeId)
{
case PointType:
pInfo->pData = malloc(sizeof(Point));
ZeroMemory(pInfo->pData, sizeof(Point));
break;
}
return pInfo->handle;
}
int DeleteType(Handle object)
{
HandleInfo *pInfo = GetHandleInfo(object);
if( NULL == pInfo )
{
return -1;
}
if( pInfo->handle != 0 )
{
free(pInfo->pData);
pInfo->pData = NULL;
pInfo->handle = 0;
return 1;
}
else
{
return 0; // Handle was already closed
}
}
void *GetObjectOfCorrectType(Handle object, Types type)
{
HandleInfo *p = GetHandleInfo(object);
if( p == NULL )
{
return NULL;
}
if( p->type != type)
{
return NULL; // handle has wrong object type
}
return p->pData;
}
void IncrementX(Handle point)
{
Point *pPoint = (Point *) GetObjectOfCorrectType(point, PointType);
if( pPoint == NULL )
{
return;
}
pPoint->x++;
}
void PrintPoint(Handle point)
{
Point *pPoint = (Point *) GetObjectOfCorrectType(point, PointType);
if( pPoint == NULL )
{
return;
}
printf("Point has x: %d y: %d", pPoint->x, pPoint->y);
}
//Private.C
#包括“stdafx.h”
#包括
#包含//用于零内存
#包括“Public.h”
类型定义结构
{
LPVOID-pData;
类型;
把手;
}HandleInfo;
类型定义结构
{
int x;
int-y;
}点;
HandleInfo*已定位;
int HandleBuffer=0xffff;
无符号字符bInit=0;
HandleInfo*GetFreeHandle()
{
int i;
如果(!bInit)
{
pAllocated=(HandleInfo*)malloc(尺寸)(HandleInfo)*把手缓冲器);
bInit=1;
零内存(pAllocated,sizeof(HandleInfo)*HandleBuffer);
}
对于(i=0;i处理)
{
pInfo->handle=i+1;
返回pInfo;
}
}
返回NULL;
}
HandleInfo*GetHandleInfo(手柄h)
{
if(h=把手缓冲器-1)
{
返回NULL;
}
返回(pAllocated+h-1);
}
句柄CreateType(类型typeId)
{
HandleInfo*pInfo;
pInfo=GetFreeHandle();
if(NULL==pInfo)
{
返回-1;
}
pInfo->type=typeId;
开关(类型ID)
{
案例点类型:
pInfo->pData=malloc(sizeof(Point));
零内存(pInfo->pData,sizeof(Point));
打破
}
返回pInfo->handle;
}
int DeleteType(句柄对象)
{
HandleInfo*pInfo=GetHandleInfo(对象);
if(NULL==pInfo)
{
返回-1;
}
如果(pInfo->handle!=0)
{
免费(pInfo->pData);
pInfo->pData=NULL;
pInfo->handle=0;
返回1;
}
其他的
{
返回0;//句柄已关闭
}
}
void*GetObjectOfCorrectType(句柄对象,类型)
{
HandleInfo*p=GetHandleInfo(对象);
if(p==NULL)
{
返回NULL;
}
如果(p->type!=type)
{
return NULL;//句柄的对象类型错误
}
返回p->pData;
}
无效增量X(控制点)
{
点*pPoint=(点*)GetObjectOfCorrectType(点,点类型);
if(pPoint==NULL)
{
返回;
}
pPoint->x++;
}
无效打印点(句柄点)
{
点*pPoint=(点*)GetObjectOfCorrectType(点,点类型);
if(pPoint==NULL)
{
返回;
}
printf(“点有x:%d y:%d”,点->x,点->y);
}
你的,
Alois Kraus您可以有单独的公共头文件和私有头文件。有些库对此有约定:
- Xt(X11)->
header.h
和headerP.h
,例如:X11/Vendor.h
vsX11/VendorP.h
- Qt->
header.h
vsprivate/header\u p.h
,例如:qapplication.h
vsprivate/qapplication\u p.h
如果您不想使用声明方法(例如,因为您希望库用户访问结构的其他成员),则惯例是在私有成员前面加下划线,如下所示:
Handle h = CreateType(PointType);
IncrementX(h);
IncrementX(h);
PrintPoint(h);
DeleteType(h);
typedef struct {
void * _data;
} point;
当然,如果他们真的想(就像人们可以在C++中添加一个<代码> >定义私有的公共代码/代码>之前,仍然可以访问<代码>数据>代码,但是这是他们自己的责任;至少您已经指出,如果他们希望您的库按应有的方式运行,就不应该这样做。我使用这种方法是为了让客户机在其堆栈中分配模块实例
struct module_private {
int data;
}
typedef uint8_t module_t [sizeof (struct module_private) ];
客户端将能够看到私有结构内容,但如果不进行他不应该进行的转换,就无法访问它 使用以下解决方法:
#include <stdio.h>
#define C_PRIVATE(T) struct T##private {
#define C_PRIVATE_END } private;
#define C_PRIV(x) ((x).private)
#define C_PRIV_REF(x) (&(x)->private)
struct T {
int a;
C_PRIVATE(T)
int x;
C_PRIVATE_END
};
int main()
{
struct T t;
struct T *tref = &t;
t.a = 1;
C_PRIV(t).x = 2;
printf("t.a = %d\nt.x = %d\n", t.a, C_PRIV(t).x);
tref->a = 3;
C_PRIV_REF(tref)->x = 4;
printf("tref->a = %d\ntref->x = %d\n", tref->a, C_PRIV_REF(tref)->x);
return 0;
}
你可以创建一个受保护的东西.h
并在那里声明你受保护的东西,并将其包含在你的.c
文件以及你的“public”.h
文件中虽然我不认为这个问题的惯例是什么。如果需要保护,使用C++,它对于这样的东西有更高级的特性。在上面的代码之后,作用域中有一个未命名的结构定义:不能用struct something
引用它;您必须通过它的typedef namepoint
+1来引用它,如果您想在像C这样的语言中使用这种保护,那么丢失堆栈分配是您必须付出的代价。请注意,这并不能真正保护数据,它只是稍微混淆了一些东西。没有什么可以阻止某人说struct pointHack{void*privateData;}
和
#include <stdio.h>
#define C_PRIVATE(T) struct T##private {
#define C_PRIVATE_END } private;
#define C_PRIV(x) ((x).private)
#define C_PRIV_REF(x) (&(x)->private)
struct T {
int a;
C_PRIVATE(T)
int x;
C_PRIVATE_END
};
int main()
{
struct T t;
struct T *tref = &t;
t.a = 1;
C_PRIV(t).x = 2;
printf("t.a = %d\nt.x = %d\n", t.a, C_PRIV(t).x);
tref->a = 3;
C_PRIV_REF(tref)->x = 4;
printf("tref->a = %d\ntref->x = %d\n", tref->a, C_PRIV_REF(tref)->x);
return 0;
}
t.a = 1
t.x = 2
tref->a = 3
tref->x = 4