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
    vs
    X11/VendorP.h
  • Qt->
    header.h
    vs
    private/header\u p.h
    ,例如:
    qapplication.h
    vs
    private/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 name
point
+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