3

是否可以声明仅在使用该结构的 .c 文件中可见的结构类型?我知道通过将静态放在外部数据对象前面,您可以将变量的链接更改为内部。但是是否可以将static放在新结构类型的声明之前,如下所示?

static struct log{
            ...;
            ...;
};
typedef struct log log;

如果无法将结构类型(例如上面的log)设置为“私有”,是否意味着即使其他源文件不知道该结构的名称(在我的示例中为log )的存在,如果他们命名一些变量日志(假设我将链接所有目标文件),仍然可能发生意外的名称冲突?

编辑:我不熟悉编译器/链接器的工作方式。如果有一个全局变量名log,并且包含全局变量的文件链接到定义结构log的唯一源文件,那么链接时不会引起任何混淆,一个日志是变量名,而另一个日志是类型名称吗?

4

4 回答 4

9

不可以。唯一的方法struct是只在使用它的文件中提供它的定义——不要把它放在一个通用的头文件中。如果它只在一个源文件中使用,那么只需在该源文件中定义它,但如果它在多个源文件中使用,你有一个棘手的问题:你可以在每个源文件中定义它,但这很脆弱,因为你有当您进行任何更改时,请记住更改它的每个实例;或者,您可以在私有头文件中定义它,并确保只有那些源文件包含私有头文件。

不同源文件中的名称冲突是可以的,只要它们不尝试以任何方式相互交互。如果您在一个文件中有一个struct log定义,而在另一个文件中有不同的定义struct log,则永远不要将一个传递log给另一个。在 C 中,结构名称不会成为目标文件中任何符号名称的一部分——特别是,没有函数名称的名称修饰以包含参数类型(就像 C++ 那样),因为函数重载在 C 中是非法的。

于 2012-10-31T20:20:27.127 回答
3

No.static是一种存储类型;将其应用于变量声明之外的类型是没有意义的。

如果您不想struct log在头文件中定义,则不必。只需将 typedef 编写为:

typedef struct log log;

就足够了,只要你只处理log *指针。但是,您将需要结构的完整定义来声明 a log(或 take sizeof(log)),因为结构的大小取决于它包含的内容。

关于名称冲突,请记住结构和类型不是由链接器管理的。链接器只关心全局可见的符号,例如函数和变量。话虽如此,您可能应该为您的类型名称应用前缀(例如,mylib_log_t)以避免混淆,特别是因为log它是标准库中的数学函数。

于 2012-10-31T20:22:53.087 回答
0

你有理由写这个:

static int a;

因为它阻止链接器将它与a其他地方定义的结合起来。链接器
与s无关,因此不用担心放入不同的c文件。 只要它在不同的c文件中,就不会有名称混淆。struct

于 2012-10-31T20:28:41.203 回答
0

这一般是不可能的。但我可以想到一个可能适用于某些编译器的 hack。

这很难做到的原因是因为 C 编译器需要知道结构是什么样的,以便生成对以结构实例作为参数的函数的调用。

因此,假设您定义了一个具有以下标头的库:

struct foo {
    int32_t a, b;
};

foo make_foo(int arg);

foo do_something(foo p1, foo p2);

然后编译一个调用 的程序do_something,你的编译器通常需要知道 foo 的结构是什么样的,以便它可以将它作为参数传递。编译器可以在这里做各种奇怪的事情,比如通过寄存器传递结构的一部分,通过堆栈传递一部分,所以它真的需要知道结构是什么样的。

但是,我相信在某些编译器中,可以指示结构应该完全通过堆栈传递。例如,regparm(0)如果您将 i386 作为目标架构 ( docs ),则 function 属性应该适用于 GCC。

在这种情况下,应该可以执行以下操作:创建头文件的“公共版本”,然后在该文件中,而不是布置完整的结构,而是创建它的未分化版本:

struct foo {
    uint8_t contents[SIZE_OF_STRUCT_FOO];
}

当您以通常的方式定义结构时,返回的SIZE_OF_STRUCT_FOO内容在哪里。sizeof(struct foo)然后,您基本上是在说“foo”是一个带有SIZE_OF_STRUCT_FOO字节的结构。然后,只要调用约定以相同的方式处理这两个结构,它就应该可以工作。

于 2014-10-27T18:08:26.050 回答