声明在结构中定义的变量

时间:2012-10-08 14:21:22

标签: c struct alias

考虑ModuleA中的以下结构已定义

typedef struct{
    int A;
    int B;
    int C[4];
}myStructType;

myStructType MyStruct;

如果我想使用ModuleB中的这个结构,那么我将声明 ModuleA标题中的结构,如下所示:

extern myStructType MyStruct;

到目前为止,这么好。其他模块可以通过包含Module A头文件来读写MyStruct。

现在的问题是:

如何声明仅模块A头文件中的部分结构?例如,如果我希望ModuleB能够读取和编写MyStruct.C(或者,为了使事情变得更容易,可能是MyStruct.A或MyStruct.B),但不一定知道它在结构中或者知道元素A和B.

编辑:我可能还应该指定这将在嵌入式系统中进行,它在编译时基本上完成所有内存分配,因此我们可以非常自信地在编译时知道MyStruct所在的位置(并且它不是要四处走动。)

Edit2:我还要澄清一点,我不一定试图阻止其他模块访问结构的某些部分,而是我试图允许其他模块可以访问单个元素而无需执行MyStruct.Whatever,因为其他模块可能只关心单个元素而不是整个结构。

6 个答案:

答案 0 :(得分:3)

你必须封装它,即创建一个私有变量,如:

static myStructType the_struct;

在某个C文件中,然后提供API以访问这些部分:

int * getC(void)
{
  return the_struct.C;
}
然后,通过调用

,这将允许其他C文件访问整数数组
int *some_c = getC();
some_c[0] = 4711;

或其他什么。当然,通过更明确地返回数组的长度可以使它更“严格”,我的目标是最小化解决方案。

答案 1 :(得分:2)

虽然理论上这个解决方案的清洁度可能存在一些问题(例如结构对齐),但实际上它通常在编译时有效,如果不编译,你可以改变结构以使其编译: / p>

#include <stddef.h>

#define C_ASSERT(expr) extern char CAssertExtern[(expr)?1:-1]

// You keep this definition private to module A (e.g. in a .c file):
typedef struct
{
    int A;
    int B;
    int C[4];
} PrivateStruct;

// You expose this definition to all modules (in an .h file):
typedef struct
{
    char reserved[2*sizeof(int)];
    int C[4];
} PublicStruct;

// You put these in module A (in a .c file):
C_ASSERT(sizeof(PrivateStruct) == sizeof(PublicStruct));
C_ASSERT(offsetof(PrivateStruct,C) == offsetof(PublicStruct,C));

int main(void)
{
  return 0;
}

在公共.h文件中,您可以向全世界介绍全局变量类型:

extern PublicStruct MyStruct; // It's "PrivateStruct MyStruct;" in module A

如果两个结构定义不同步,则会出现编译时错误(matchmismatch)。

您可能需要手动定义PublicStruct的保留部分的大小,可能是通过反复试验。

你明白了。

答案 2 :(得分:1)

长话短说 - 你做不到。为了使它更长一些,你无法可靠地做到这一点。

答案 3 :(得分:1)

您可以尝试使用一种吸气剂:

在ModuleA中

typedef struct{
    int A;
    int B;
    int C[4];
}myStructType;

myStructType MyStruct;

int getA()
{
    return MyStruct.A;
}

等等。

而是切换到c ++

答案 4 :(得分:0)

你不能完全按照你所描述的那样做,但是将结构用作标题是很常见的,它与缓冲区是连续的,只有特定模块知道它的内部结构。

这个结构是什么标题很明显,但它仍然作为一个例子:

typedef struct _FILE_NOTIFY_INFORMATION {
  ULONG NextEntryOffset;
  ULONG Action;
  ULONG NameLength;
  ULONG Name[1];
} FILE_NOTIFY_INFORMATION, *PFILE_NOTIFY_INFORMATION;

此结构(来自Microsofts NativeSDK)被设计为可变长度缓冲区的标头。所有模块都可以通过查看NameLength来计算缓冲区的长度,但是您可以使用此方法将任何内容存储在缓冲区中。这可能只是由特定模块知道,而其他模块只是使用长度来复制它等等。

答案 5 :(得分:0)

如果不是为了隐藏而是为了构造,那么就构建它。例如:

moduleA.h:

typedef struct{
    int A;
}myStructModuleAType;

extern myStructModuleAType myStructModuleA;

moduleA.c:

myStructModuleAType myStructModuleA;

moduleB.h:

typedef struct{
    int B;
}myStructModuleBType;

extern myStructModuleBType myStructModuleB;

moduleB.c:

myStructModuleBType myStructModuleB;

main.h:

#include "moduleA.h"
#include "moduleB.h"

typedef struct{
    myStructModuleAType * pmyStructModuleA;
    myStructModuleBType * pmyStructModuleB;
    int C[4];
}myStructType;

extern myStructType myStruct;

main.c中:

#include "main.h"

myStructType myStruct;

myStructType myStruct = { 
  .pmyStructModuleA = &myStructModuleA
  .pmyStructModuleB = &myStructModuleB
};