3

我有一个看起来像这样的小数据隐藏模块:

/** mydata.h */
struct _mystruct_t;
typedef struct _mystruct_t mystruct;

mystruct *newMystruct();
void freeMystruct( mystruct** p );

/** mydata.c */
#include "mydata.h"
struct _mystruct_t {
    int64_t data1;
    int16_t data2;
    int16_t data3;
};
// ... related definitions ... //

在大多数情况下,这就是我想要的;虽然简单,但结构有严格的一致性要求,我真的不想提供对数据成员的访问。

问题是在客户端代码中,我想将该结构包含在另一个我想在堆栈上分配的结构中。现在我正在跳过箍来释放mystruct*一些客户端代码中的 s 。因为a)mystruct非常小,我真的不认为它会很快变大,并且b)如果我改变mystruct,客户端代码必须重新编译不是问题,我想公开mystruct的大小(即在标题中)。

我考虑过的两种可能性:

/** mydata.h */
typedef struct {
    // SERIOUSLY DON'T ACCESS THESE MEMBERS
    int64_t data1;
    int16_t data2;
    int16_t data3;
} mystruct;

我认为这里的缺点不言自明。

或者

/** mydata.h */
#define SIZEOF_MYSTRUCT (sizeof(int64_t)+sizeof(int16_t)+sizeof(int16_t))
// everything else same as before...

/** mydata.c */
// same as before...
_Static_assert (SIZEOF_MYSTRUCT == sizeof(mystruct), "SIZEOF_MYSTRUCT is incorrect")

当然这似乎并不理想,因为我必须手动更新这个值,而且我不知道结构的对齐是否/如何实际上导致这个不正确(我在写这个问题时想到了静态断言,它部分解决了这种担忧)。

其中之一是首选吗?或者更好的是,是否有一些巧妙的技巧可以在标题中提供实际的结构定义,而稍后以某种方式隐藏访问成员的能力?

4

3 回答 3

1

您可以创建.h分发给最终用户的不同文件,将您的秘密结构定义为字节数组(您不能在没有加密/校验和的情况下隐藏数据,而不仅仅是说“这里有一些字节”):

typedef struct {
    unsigned char data[12];
} your_struct;

您只需要确保所有编译器和选项的两个结构都相同,因此__declspec(align())在您的库代码中使用 (for VC),例如:

// Client side
__declspec(align(32)) typedef struct {
    int64_t data1;
    int16_t data2;
    int16_t data3;
} mystruct;

防止结构长度为 16B 而不是通常预期的 12B。或者只是使用/Zp编译器选项。

于 2014-10-03T15:24:37.910 回答
1

我将继续使用生成的配置时间来#define描述 的大小,mystruct并可能typedef char[SIZEOF_MYSTRUCT] opaque_mystruct简化为 mystruct 创建占位符。

可能的想法configure time actions值得一些解释。总体思路是

  1. 将 的定义mystruct放入一个私有的、未导出但仍然是分布式的标头中,
  2. 在库之前创建一个正在构建和执行的小型测试应用程序。测试应用程序将#include 私有头文件,并打印sizeof (mystruct)给定编译器和编译选项的实际值
  3. 创建一个适当的脚本,该脚本将创建一个config.h带有#define SIZEOF_MYSTRUCT <calculated_number>opaque_mystruct 并可能定义的库。

例如cmake,使用像样的构建系统gnu autotools或任何其他支持configurestage 的系统来自动化这些步骤是很方便的。实际上,所有提到的系统都有内置的工具,可以将整个任务简化为调用几个预定义的宏。

于 2014-10-03T15:26:49.463 回答
-1

我一直在研究和思考,并把我的一个潜在答案带到了一个新的水平;我认为它解决了我所有的担忧。请批评。

/** in mydata.h */
typedef const struct { const char data[12]; } mystruct;
mystruct createMystruct();
int16_t exampleMystructGetter( mystruct *p );
// other func decls operating on mystruct ...


/** in mydata.c */
typedef union {
    mystruct public_block;
    struct mystruct_data_s {
        int64_t d1;
        int16_t d2
        int16_t d3;
    } data;
} mystruct_data;

// Optionally use '==' instead of '<=' to force minimal space usage
_Static_assert (sizeof(struct mystruct_data_s) <= sizeof(mystruct), "mystruct not big enough");

mystruct createMystruct(){
    static mystruct_data mystruct_blank = { .data = { .d1 = 1, .d2 = 2, .d3 = 3 } };
    return mystruct_blank.public_block;
}

int16_t exampleMystructGetter(mystruct *p) {
    mystruct_data *a = (mystruct_data*)p;
    return a->data.d2;
}

在 gcc 4.7.3 下编译时没有警告。通过 getter 创建和访问的简单测试程序也可以按预期编译和工作。

于 2014-10-03T19:32:54.430 回答