关于C中1元素数组的typedef [英] Regarding typedefs of 1-element arrays in C

查看:95
本文介绍了关于C中1元素数组的typedef的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有时,在C语言中,您需要这样做:

Sometimes, in C, you do this:

typedef struct foo {
   unsigned int some_data;
} foo; /* btw, foo_t is discouraged */

要在OO排序中使用这种新类型,您可能需要像下面这样的alloc/free对:

To use this new type in an OO-sort-of-way, you might have alloc/free pairs like these:

foo *foo_alloc(/* various "constructor" params */);
void foo_free(foo *bar);

或者,也可以使用初始化/清除对(可能返回错误代码):

Or, alternatively init/clear pairs (perhaps returning error-codes):

int foo_init(foo *bar, /* and various "constructor" params */);
int foo_clear(foo *bar);

我已经看到以下用法,尤其是在MPFR库中:

I have seen the following idiom used, in particular in the MPFR library:

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 */

分配/空闲和初始化/清除对现在显示为:

The alloc/free and init/clear pairs now read:

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);

现在您可以像这样使用它了(例如,init/clear对):

Now you can use it all like this (for instance, the init/clear pairs):

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. */
}

备注:初始化/清除对似乎允许使用更通用的方式初始化和清除对象.与alloc/free对相比,init/clear对要求已经构造了浅"对象. 深层"构造是使用init完成的.​​

Remarks: The init/clear pair seems to allow for a more generic way of initializing and clearing out objects. Compared to the alloc/free pair, the init/clear pair requires that a "shallow" object has already been constructed. The "deep" construction is done using init.

问题:1元素数组"type-idiom"是否存在任何明显的陷阱?

Question: Are there any non-obvious pitfalls of the 1-element array "type-idiom"?

推荐答案

这非常聪明(但请参见下文).

This is very clever (but see below).

它鼓励产生误导性的想法,即C函数参数可以通过引用传递.

It encourages the misleading idea that C function arguments can be passed by reference.

如果我在C程序中看到此内容:

If I see this in a C program:

foo bar;
foo_init(bar);

我知道对foo_init的调用不会修改bar的值.我还知道代码没有初始化bar的值时就将其传递给函数,这很可能是未定义的行为.

I know that the call to foo_init does not modify the value of bar. I also know that the code passes the value of bar to a function when it hasn't initialized it, which is very probably undefined behavior.

除非我碰巧知道foo是数组类型的typedef.然后我突然意识到foo_init(bar)不是传递bar value ,而是传递其第一个元素的地址.现在,每次我看到涉及类型foo或类型为foo的对象时,我都必须考虑如何将foo定义为单元素数组的typedef.代码.

Unless I happen to know that foo is a typedef for an array type. Then I suddenly realize that foo_init(bar) is not passing the value of bar, but the address of its first element. And now every time I see something that refers to type foo, or to an object of type foo, I have to think about how foo was defined as a typedef for a single-element array before I can understand the code.

这是试图使C看起来像不是什么,

It is an attempt to make C look like something it's not, not unlike things like:

#define BEGIN {
#define END }

,依此类推.而且,它不会使代码更容易理解,因为它使用了C不直接支持的功能.这样会导致代码难以理解(尤其是熟悉C的读者),因为您必须同时理解定制的声明使整个过程正常工作的底层C语义.

and so forth. And it doesn't result in code that's easier to understand because it uses features that C doesn't support directly. It results in code that's harder to understand (especially to readers who know C well), because you have to understand both the customized declarations and the underlying C semantics that make the whole thing work.

如果要传递指针,只需传递指针,然后显式执行即可.例如,请参见在<stdio.h>中定义的各种标准功能中使用FILE*.没有试图将指针隐藏在宏或typedef后面,并且C程序员使用该接口已有几十年了.

If you want to pass pointers around, just pass pointers around, and do it explicitly. See, for example, the use of FILE* in the various standard functions defined in <stdio.h>. There is no attempt to hide pointers behind macros or typedefs, and C programmers have been using that interface for decades.

如果您想编写看起来像是通过引用传递参数的代码,请定义一些类似于函数的宏,并为它们指定全大写的名称,以便有知识的读者可以了解正在发生的事情.

If you want to write code that looks like it's passing arguments by reference, define some function-like macros, and give them all-caps names so knowledgeable readers will know that something odd is going on.

我在上面说这是聪明".我想起了我第一次学习C语言时做过的事情:

I said above that this is "clever". I'm reminded of something I did when I was first learning the C language:

#define EVER ;;

这让我写了一个无限循环为:

which let me write an infinite loop as:

for (EVER) {
    /* ... */
}

当时,我认为它很聪明.

At the time, I thought it was clever.

我仍然认为这很聪明.我只是不再认为那是一件好事.

I still think it's clever. I just no longer think that's a good thing.

这篇关于关于C中1元素数组的typedef的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆