我已经看到以下两种在C API中声明不透明类型的样式.使用一种风格而不是另一种风格有明显的优势吗?
// foo.h
typedef struct foo * fooRef;
void doStuff(fooRef f);
// foo.c
struct foo {
int x;
int y;
};
Run Code Online (Sandbox Code Playgroud)
// foo.h
typedef struct _foo foo;
void doStuff(foo *f);
// foo.c
struct _foo {
int x;
int y;
};
Run Code Online (Sandbox Code Playgroud) 在为嵌入式系统编程时,通常不允许使用malloc().大部分时间我都能够处理这个问题,但有一件事让我感到恼火:它使我无法使用所谓的"不透明类型"来启用数据隐藏.通常我会做这样的事情:
// In file module.h
typedef struct handle_t handle_t;
handle_t *create_handle();
void operation_on_handle(handle_t *handle, int an_argument);
void another_operation_on_handle(handle_t *handle, char etcetera);
void close_handle(handle_t *handle);
// In file module.c
struct handle_t {
int foo;
void *something;
int another_implementation_detail;
};
handle_t *create_handle() {
handle_t *handle = malloc(sizeof(struct handle_t));
// other initialization
return handle;
}
Run Code Online (Sandbox Code Playgroud)
你去:create_handle()执行malloc()来创建'实例'.通常用于防止必须使用malloc()的构造是更改create_handle()的原型,如下所示:
void create_handle(handle_t *handle);
Run Code Online (Sandbox Code Playgroud)
然后调用者可以这样创建句柄:
// In file caller.c
void i_am_the_caller() {
handle_t a_handle; // Allocate a handle on the stack instead of malloc()
create_handle(&a_handle);
// ... a_handle …Run Code Online (Sandbox Code Playgroud) 有人对"不透明类型"有什么好的解释吗?我在上下文中看到了这个术语CFBundleRef,他们说的是:"CFBundleRef opaque type".这是一种只读的类型吗?
我已经定义了一个不透明的结构和相关的API,如下所示:
typedef struct foo foo;
foo *create_foo(...);
delete_foo(foo *f);
Run Code Online (Sandbox Code Playgroud)
我无法在我的c文件中定义结构.给出重新定义错误.
typedef struct foo {
int implementation;
}foo;
Run Code Online (Sandbox Code Playgroud)
我可以在没有typedef的c文件中使用foo,但我想要typedef(即直接使用它作为foo*).有办法吗?
在设计C接口时,通常只允许.h用户程序需要知道的公共接口().
因此,例如,如果用户程序不需要知道它们,则结构的内部组件应该保持隐藏.这确实是一种很好的做法,因为结构的内容和行为将来可能会发生变化,而不会影响界面.
实现该目标的一个好方法是使用不完整的类型.
typedef struct foo opaqueType;
现在opaqueType可以构建仅使用指针的接口,而无需用户程序知道内部工作struct foo.
但有时,可能需要静态地(通常在堆栈上)分配此类结构,以解决性能和内存碎片问题.显然,上面的结构,opaqueType是不完整的,所以它的大小是未知的,所以它不能静态分配.
解决方法是分配"shell类型",例如:
typedef struct { int faketable[8]; } opaqueType;
上面的构造强制执行大小和对齐,但不会进一步描述结构真正包含的内容.因此它符合保持"不透明"类型的目标.
它主要起作用.但在一种情况下(GCC 4.4),编译器抱怨它打破了严格别名,并且它生成了错误的二进制文件.
现在,我已经阅读了大量关于严格混叠的内容,所以我想我现在明白这意味着什么.
问题是:有没有办法定义一个opaque类型,它仍然可以在堆栈上分配,而不会破坏严格的别名规则?
请注意,我已经尝试了这篇优秀文章中描述的union方法,但它仍然会生成相同的警告.
另请注意,visual,clang和gcc 4.6及更高版本不会抱怨并且可以正常使用此构造.
[编辑]信息补充:
根据测试,问题只发生在以下情况:
.c文件中的私有类型.如果他们是同一个联盟的一部分,那显然无关紧要.公共类型是否包含无关紧要char.最后,我的目标是C90.也许C99如果真的没有选择.
我正在使用此代码.
var audioUnit:AudioUnit = AudioUnit()
Run Code Online (Sandbox Code Playgroud)
但是在Xcode 7.3(Swift 2.2)中,我收到了这个警告.知道为什么吗?我怎么能摆脱它呢?
NB我使用nil然后我的程序崩溃了.
C99 - 特别是第6.2.6.1节第4段 - 规定允许将对象表示复制到unsigned char数组中:
struct {
int foo;
double bar;
} baz;
unsigned char bytes[sizeof baz];
// Do things with the baz structure.
memcpy(bytes, &baz, sizeof bytes);
// Do things with the bytes array.
Run Code Online (Sandbox Code Playgroud)
我的问题:我们不能通过简单的转换避免额外的内存分配和复制操作吗?例如:
struct {
int foo;
double bar;
} baz;
unsigned char *bytes = (void *)&baz;
// Do stuff with the baz structure.
// Do things with the bytes array.
Run Code Online (Sandbox Code Playgroud)
当然,需要跟踪大小,但这首先是合法的,还是属于实现定义或未定义行为的范围?
我问,因为我正在实现一个类似的算法qsort,我希望它适用于任何类型的数组,就像它qsort一样.
我希望通过这项研究了解CoreFoundation CGColor对象的内部结构.我可以从免费的石英项目中找到CGColor结构的样本定义,它似乎与IOS声明相符(依赖于我的研究).
typedef struct CGColor {
CFRuntimeBase obj;
CFTypeID colorID;
CGColorSpaceRef colorSpace;
CGPatternRef pattern;
size_t numberOfComponents;
CGFloat *components;
} *CGColorRef;
Run Code Online (Sandbox Code Playgroud)
(colorID字段由free quartz命名为nextID,但我认为它是IOS的唯一标识,因此它不是一种下一个标识符.)
保持全局线程安全唯一值,对于创建并分配给colorID成员的每个CGColor对象,该值增加1.只有未记录的CGColorGetIdentifier()函数返回此值.(我猜测单调增加id值,它可以在设备与校准颜色查找之间进行转换时提高性能,反之亦然.)
我检查了CoreGraphics及其资源库.我发现只有ripc_GetColor(libRIP.A.dylib)函数调用CGColorGetIdentifier()函数.
调用CGColorGetIdentifier的堆栈;(希望能帮助推断colorID)
0 com.apple.CoreGraphics CGColorGetIdentifier + 0
1 libRIP.A.dylib ripc_GetColor + 112
2 libRIP.A.dylib ripc_DrawGlyphs + 1740
3 com.apple.CoreGraphics CGContextDelegateDrawGlyphs + 108
4 com.apple.CoreGraphics drawGlyphs + 284
5 com.apple.CoreGraphics CGContextShowGlyphsWithAdvances + 208
Run Code Online (Sandbox Code Playgroud)
对于当前的颜色图形上下文操作,ripc_GetColor()计算当前笔触/填充颜色的一些变换,并使用此颜色的referenceID和colorID缓存这些变换.
因此,对于下一个图形上下文操作,ripc_GetColor()将先前缓存的当前引用和colorID值进行比较,以跳过已为最后一个图形上下文操作缓存的颜色转换.
我们知道在创建另一个对象时可以使用已发布对象的引用(内存地址).因此,仅检查引用将不足以使相同的颜色对象有效,但我们需要比较内容或某种哈希值.因此,我们可以为此目的使用唯一标识符值.
但是,标识符可以用于单个对象及其引用,因此仅比较ID就足够了.但是,使用了refs和id.我不认为工程师忽视了这么简单和至关重要的事情.
所以,我试图找出比较id和refs的必要性,同时只比较id就足够了.
是否遗留了以前的方法,所以不能完全放弃?
在下面的例子中,如何正确调用~CImpl,但是当需要移动类时,编译器说它有一个不完整的类型?
如果Impl的声明被移动到它工作的标题,我的问题是如何将析构函数调用为好,所以它似乎不是类型不完整,但移动时出现问题.
档案:C.hpp
#include <memory>
class Impl;
class C
{
public:
C();
~C();
C(C&&) = default;
C& operator=(C&&) = default;
std::unique_ptr<Impl> p;
};
Run Code Online (Sandbox Code Playgroud)
档案C.cpp
#include "C.hpp"
#include <iostream>
using namespace std;
class Impl
{
public:
Impl() {}
virtual ~Impl() = default;
virtual void f() = 0;
};
class CImpl: public Impl
{
public:
~CImpl()
{
cout << "~CImpl()" << endl;
}
void f()
{
cout << "f()" << endl;
}
};
C::C():
p(new CImpl())
{}
C::~C()
Run Code Online (Sandbox Code Playgroud)
file:main.cpp
#include <iostream>
#include …Run Code Online (Sandbox Code Playgroud) 库定义了不透明的数据类型:
\n\nstruct OpaqueStruct;\nRun Code Online (Sandbox Code Playgroud)\n\n并且客户端代码必须获取并释放OpaqueStruct*. 我可以访问库源。
不幸的是,既不能存储该指针shared_ptr,也unique_ptr不能存储该指针,从而出现错误: invalid application of \xe2\x80\x98sizeof\xe2\x80\x99 to incomplete type。
我能想到的最好的办法就是从这篇文章中借用finally守卫 。
\n\n如何将 RAII 用于不透明结构指针?
\nopaque-pointers ×10
c ×6
c++ ×2
c++11 ×2
ios ×2
struct ×2
typedef ×2
audiounit ×1
c++14 ×1
coding-style ×1
embedded ×1
iphone ×1
objective-c ×1
pimpl-idiom ×1
stack ×1
swift ×1
swift2 ×1