我在头文件中定义了一个结构,如下所示:
typedef struct {
void *data;
} point;
我想让其他人直接访问*数据,所以我想我会在.c文件中声明结构,并在头文件中使用类似extern typedef struct point;
的内容。但是,这不起作用。
实现这一目标的最佳方式是什么?
答案 0 :(得分:14)
在您的(公共)标头文件中:
typedef struct point point;
在.c
文件中:
struct point
{
void *data;
};
请注意,代码的用户将无法再在堆栈上创建point
,因为编译器不知道它有多大。您可能必须提供point_create()
函数,该函数分配内存并将其地址返回给调用者。
答案 1 :(得分:4)
使用C ++
// 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);
正如您所看到的,您可以使用通用方法创建和删除在枚举中定义的对象。然后,使用该对象的方法将需要查找整数句柄以获取存储实际数据的元数据对象。 如果您管理的对象很小,则此设计效率不高,因为对于每个对象,需要存储对象类型,句柄值和指向实际数据的指针的第二个对象。 但是你会获得更强大的安全保障,例如
您的Api的典型用法可能如下所示:
Handle h = CreateType(PointType);
IncrementX(h);
IncrementX(h);
PrintPoint(h);
DeleteType(h);
在private.cpp中有超级秘密实现,其中存在Handle查找数组和一些辅助方法:
// 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);
}
此致, Alois Kraus
答案 2 :(得分:3)
这是指向实现的指针或 pimpl 成语。有关C ++的教程,请参阅http://en.wikibooks.org/wiki/C++_Programming/Idioms#Pointer_To_Implementation_.28pImpl.29,但该想法也适用于C语言。
答案 3 :(得分:2)
typedef struct {
/* private members; don't access directly */
void *data;
} point;
答案 4 :(得分:0)
您可以拥有单独的公共标头和私有标头文件。有些图书馆有这样的惯例:
header.h
和headerP.h
,例如:X11/Vendor.h
vs X11/VendorP.h
header.h
vs private/header_p.h
,例如:qapplication.h
vs private/qapplication_p.h
答案 5 :(得分:0)
如果您不想使用声明方法(例如,因为您希望库用户访问结构的其他成员),则通常会在私有成员前加上下划线,如下所示:
typedef struct {
void * _data;
} point;
当然人们仍然可以访问_data
,如果他们真的想要(就像人们可以通过在其包含之前添加#define private public
来访问C ++中的私人数据),但这是他们自己的责任;至少你已经表明,如果他们希望你的图书馆能够按照自己的意愿行事,他们就不应该这样做。
答案 6 :(得分:0)
我使用这种方法让客户端在他的STACK中分配模块实例。
struct module_private {
int data;
}
typedef uint8_t module_t [sizeof (struct module_private) ];
客户端将能够看到私有结构内容,但不能在不进行他不应该进行的强制转换的情况下访问它。
答案 7 :(得分:0)
使用以下解决方法:
#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