有时候,在C中,你这样做:
typedef struct foo {
unsigned int some_data;
} foo; /* btw, foo_t is discouraged */
Run Code Online (Sandbox Code Playgroud)
要在OO-sort-way中使用这种新类型,你可能有这样的alloc/free对:
foo *foo_alloc(/* various "constructor" params */);
void foo_free(foo *bar);
Run Code Online (Sandbox Code Playgroud)
或者,或者init/clear对(可能返回错误代码):
int foo_init(foo *bar, /* and various "constructor" params */);
int foo_clear(foo *bar);
Run Code Online (Sandbox Code Playgroud)
我已经看到使用了以下习语,特别是在MPFR库中:
struct foo {
unsigned int some_data;
};
typedef struct foo foo[1]; /* <- notice, 1-element array */
typedef struct foo *foo_ptr; /* let's create a ptr-type */
Run Code Online (Sandbox Code Playgroud)
alloc/free和init/clear对现在读取:
foo_ptr foo_alloc(/* various "constructor" params */);
void foo_free(foo_ptr bar);
int foo_init(foo_ptr bar, /* and various "constructor" params */);
int foo_clear(foo_ptr bar);
Run Code Online (Sandbox Code Playgroud)
现在你可以像这样使用它(例如,init/clear对):
int main()
{
foo bar; /* constructed but NOT initialized yet */
foo_init(bar); /* initialize bar object, alloc stuff on heap, etc. */
/* use bar */
foo_clear(bar); /* clear bar object, free stuff on heap, etc. */
}
Run Code Online (Sandbox Code Playgroud)
备注:init/clear对似乎允许更通用的方式初始化和清除对象.与alloc/free对相比,init/clear对要求已经构造了"浅"对象."深度"构造使用init完成.
问题:1元素数组"type-idiom"是否有任何非明显的缺陷?
Kei*_*son 11
这非常聪明(但见下文).
它鼓励误导的观点,即C函数参数可以通过引用传递.
如果我在C程序中看到这个:
foo bar;
foo_init(bar);
Run Code Online (Sandbox Code Playgroud)
我知道调用foo_init
不会修改值bar
.我也知道代码在bar
没有初始化时将值传递给函数,这很可能是未定义的行为.
除非我碰巧知道这foo
是一个数组类型的typedef.这时我突然意识到,foo_init(bar)
不流通价值的bar
,但是它的第一个元素的地址.现在,每当我看到引用类型foo
或类型对象的内容时foo
,我都要考虑foo
在理解代码之前如何定义为单元素数组的typedef.
这是一种让C看起来不像它的东西的尝试,与以下内容不同:
#define BEGIN {
#define END }
Run Code Online (Sandbox Code Playgroud)
等等.并且它不会导致代码更容易理解,因为它使用C不直接支持的功能.这会导致代码是很难理解(尤其是给谁知道的C以及读者),因为你必须要了解双方的定制声明和底层的C语义使整个事情的工作.
如果你想传递指针,只需传递指针,并明确地做.例如,参见FILE*
在中定义的各种标准函数中的使用<stdio.h>
.没有尝试隐藏宏或typedef背后的指针,C程序员已经使用该接口数十年了.
如果你想编写看起来像是通过引用传递参数的代码,定义一些类似函数的宏,并给它们全部大写名称,这样知识渊博的读者就会知道奇怪的事情正在发生.
我在上面说过,这是"聪明的".我想起了我第一次学习C语言时所做的事情:
#define EVER ;;
Run Code Online (Sandbox Code Playgroud)
这让我写了一个无限循环:
for (EVER) {
/* ... */
}
Run Code Online (Sandbox Code Playgroud)
那时,我觉得它很聪明.
我仍然觉得它很聪明.我不再认为这是件好事.
归档时间: |
|
查看次数: |
311 次 |
最近记录: |