如何在通用标头中typedef实现定义的结构? [英] How do I typedef an implementation-defined struct in a generic header?
问题描述
我有一个C项目,旨在将其移植到各种(PC和嵌入式)平台上.
应用程序代码将使用各种调用,这些调用将具有特定于平台的实现,但共享一个通用的(通用)API以帮助实现可移植性.我正在尝试确定最合适的方法来声明函数原型和结构.
这是到目前为止我要提出的:
main.c:
#include "generic.h"
int main (int argc, char *argv[]) {
int ret;
gen_t *data;
ret = foo(data);
...
}
generic.h:(与平台无关的包含项)
typedef struct impl_t gen_t;
int foo (gen_t *data);
impl.h:(特定于平台的声明)
#include "generic.h"
typedef struct impl_t {
/* ... */
} gen_t;
impl.c:(特定于平台的实现)
int foo (gen_t *data) {
...
}
内部版本:
gcc -c -fPIC -o platform.o impl.c
gcc -o app main.c platform.o
现在,这似乎可以正常工作,因为它可以编译.但是,由于通常不会在typedef
别名之外进行访问,因此我通常不标记结构.这是一个小巧的选择,但我想知道是否可以通过匿名结构实现相同的效果?
我也在询问后代,因为我搜索了一段时间,发现的最接近答案是:( 这些似乎都没有特别吸引人,而且绝对不是我的风格.虽然我不想游刃有余,但是当可能有更好的方法来准确实现我的想法时,我也不想出现冲突的风格.因此,我认为typedef解决方案是在正确的轨道上,而这只是我剩下的struct标记. 有想法吗? 您当前的技术是正确的.尝试使用匿名的(未标记的) 在 user3629249 说: 头文件包含的顺序意味着 对于问题中显示的标题,这种观察是不正确的;对于示例 关键是显示的接口函数采用或返回类型为 后者也为类型 因此, 其中(对于此示例) 对于始终使用
在C ++程序中, 表示名称 我避免在类型上使用 *请参见 POSIX标准中的名称空间. I have a C project that is designed to be portable to various (PC and embedded) platforms. Application code will use various calls that will have platform-specific implementations, but share a common (generic) API to aid in portability. I'm trying to settle on the most appropriate way to declare the function prototypes and structures. Here's what I've come up with so far: main.c: generic.h: (platform-agnostic include) impl.h: (platform-specific declaration) impl.c: (platform-specific implementation) Build: Now, this appears to work... in that it compiles OK. However, I don't usually tag my structures since they're never accessed outside of the I'm also asking for posterity, since I searched for a while and the closest answer I found was this: (Link) In my case, that wouldn't be the right approach, as the application specifically shouldn't ever include the implementation headers directly -- the whole point is to decouple the program from the platform. I see a couple of other less-than-ideal ways to resolve this, for example: generic.h: Neither of these seems particularly appealing, and definitely not my style. While I don't want to swim upstream, I also don't want conflicting style when there might be a nicer way to implement exactly what I had in mind. So I think the typedef solution is on the right track, and it's just the struct tag baggage I'm left with. Thoughts? Your current technique is correct. Trying to use an anonymous (untagged) In a comment, user3629249 said: The order of the header file inclusions means there is a forward reference to the struct by the This observation is incorrect for the headers shown in the question; it is accurate for the sample The key point is that the interface functions shown take or return pointers to the type The latter also introduces the alias The original This code cannot be compiled with It would not compile with: because the compiler must know how big the structure is to allocate the correct space for Thus, the where (for this example) Opinion is split over whether it is better to always use in a C++ program means that the name I avoid using the * See the bottom line of the second table in The Name Space in the POSIX standard. 这篇关于如何在通用标头中typedef实现定义的结构?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!struct
会破坏您要执行的操作-您必须在任何地方公开struct
的定义的详细信息,这意味着您不再拥有不透明的数据类型.>
generic.h
文件对结构的前向引用;也就是说,在定义结构之前,先使用它.这不太可能会编译.main()
代码来说是准确的(直到添加此响应之前我才注意到).gen_t
的指针,该指针又映射为struct impl_t
指针.只要客户代码不需要为该结构分配空间,也不需要取消对结构的指针的引用来访问该结构的成员,则客户代码不需要知道该结构的细节.将结构类型声明为存在就足够了.您可以使用其中任何一个来声明struct impl_t
的存在:struct impl_t;
typedef struct impl_t gen_t;
struct impl_t
引入了别名gen_t
.另请参见 C标准的哪个部分允许和使用typedef
指针好吗?类型定义指向结构的指针.)main()
代码应该更像:#include "generic.h"
int main(int argc, char **argv)
{
gen_t *data = bar(argc, argv);
int ret = foo(data);
...
}
bar()
被定义为extern gen_t *bar(int argc, char **argv);
,因此它返回指向不透明类型gen_t
的指针.struct tagname
还是使用typedef
作为名称是更好的看法. Linux内核是不使用typedef
机制的实质性代码体.所有结构都明确地struct tagname
.另一方面,C ++消除了对显式typedef
的需要;写作:struct impl_t;
impl_t
现在是类型的名称.由于不透明的结构类型需要标记(或者您最终使用void *
进行所有操作,这在很多方面都是不利的,但是主要原因是您使用void *
失去了所有类型的安全性;请记住,typedef
引入了基础类型的别名,而不是新的独特类型的别名),这就是我在C语言中编写代码的方式来模拟C ++:typedef struct Generic Generic;
_t
后缀,因为POSIX保留_t
供实施使用 * (另请参见_t(这是一种表示某种类型的简便方法),我建议也使用一个独特的前缀:例如,对于某些项目pqr
,使用pqr_typename_t
.#include "generic.h"
int main (int argc, char *argv[]) {
int ret;
gen_t *data;
ret = foo(data);
...
}
typedef struct impl_t gen_t;
int foo (gen_t *data);
#include "generic.h"
typedef struct impl_t {
/* ... */
} gen_t;
int foo (gen_t *data) {
...
}
gcc -c -fPIC -o platform.o impl.c
gcc -o app main.c platform.o
typedef
'd alias. It's a small nit-pick, but I'm wondering if there's a way to achieve the same effect with anonymous structs?#ifdef PLATFORM_X
#include "platform_x/impl.h"
#endif
/* or */
int foo (struct impl_t *data);
struct
defeats what you're trying to do — you'd have to expose the details of definition of the struct
everywhere, which means you no longer have an opaque data type.
generic.h
file; that is, before the struct is defined, it is used. It is unlikely this would compile.main()
code (which I hadn't noticed until adding this response).gen_t
, which in turn maps to a struct impl_t
pointer. As long as the client code does not need to allocate space for the structure, or dereference a pointer to a structure to access a member of the structure, the client code does not need to know the details of the structure. It is sufficient to have the structure type declared as existing. You could use either of these to declare the existence of struct impl_t
:struct impl_t;
typedef struct impl_t gen_t;
gen_t
for the type struct impl_t
. See also Which part of the C standard allows this code to compile? and Does the C standard consider that there are one or two struct uperms
entry types in this header?main()
program in the question was:int main (int argc, char *argv[]) {
int ret;
gen_t data;
ret = foo(&data);
…
}
gen_t
as an opaque (non-pointer) type. It would work OK with:typedef struct impl_t *gen_t;
typedef struct impl_t gen_t;
data
, but the compiler cannot know that size by definition of what an opaque type is. (See Is it a good idea to typedef
pointers? for typedefing pointers to structures.)main()
code should be more like:#include "generic.h"
int main(int argc, char **argv)
{
gen_t *data = bar(argc, argv);
int ret = foo(data);
...
}
bar()
is defined as extern gen_t *bar(int argc, char **argv);
, so it returns a pointer to the opaque type gen_t
.struct tagname
or to use a typedef
for the name. The Linux kernel is one substantial body of code that does not use the typedef
mechanism; all structures are explicitly struct tagname
. On the other hand, C++ does away with the need for the explicit typedef
; writing:struct impl_t;
impl_t
is now the name of a type. Since opaque structure types require a tag (or you end up using void *
for everything, which is bad for a whole legion of reasons, but the primary reason is that you lose all type safety using void *
; remember, typedef
introduces an alias for an underlying type, not a new distinct type), the way I code in C simulates C++:typedef struct Generic Generic;
_t
suffix on my types because POSIX reserves the _t
for the implementation to use* (see also What does a type followed by _t
represent?). You may be lucky and get away with it. I've worked on code bases where types like dec_t
and loc_t
were defined by the code base (which was not part of the implementation — where 'the implementation' means the C compiler and its supporting code, or the C library and its supporting code), and both those types caused pain for decades because some of the systems where the code was ported defined those types, as is the system's prerogative. One of the names I managed to get rid of; the other I didn't. 'Twas painful! If you must use _t
(it is a convenient way to indicate that something is a type), I recommend using a distinctive prefix too: pqr_typename_t
for some project pqr
, for example.