typedef定长数组


210

我必须定义一个24位数据char[3]类型。我用来表示这种类型。我可以的typedef char[3]type24?我在代码示例中尝试过。我放入typedef char[3] type24;了头文件。编译器没有对此抱怨。但是,当我void foo(type24 val) {}在C文件中定义一个函数时,它确实抱怨了。我希望能够定义类似type24_to_int32(type24 val)而不是的函数type24_to_int32(char value[3])

Answers:


320

该typedef将是

typedef char type24[3];

但是,这可能是一个非常糟糕的主意,因为结果类型是数组类型,但是使用它的用户不会看到它是数组类型。如果用作函数参数,它将通过引用而不是通过值传递sizeof,因此它将是错误的。

更好的解决方案是

typedef struct type24 { char x[3]; } type24;

您可能还想使用unsigned char而不是char,因为后者具有实现定义的签名。


10
有没有很好的文档来描述将类型定义数组作为参数传递所涉及的极端情况?例如,如果一个函数需要一个参数type24 foo,会是什么尺寸,类型和含义foo*foo**foo&foo,和&&foo?这些年来,这些表达的含义和合法性是否发生了变化?
超级猫2012年

4
可能值得一提的是结构打包警告,因为24位数据类型可能打算映射到具有不同定义的打包语义的内容,例如RGB图像数据。
2013年

2
@ sh1:在我所知道的所有现代现实世界ABI上,即使是那些未对齐访问非常昂贵的ABI,结构所得到的对齐要求也比没有该结构的成员要强。当然,OP或使用此方法的其他任何人都应该验证我的主张,如果这与他们的程序的行为和可移植性有关。
R .. GitHub STOP HELPING ICE 2013年

4
@R。这是误导性的一部分-在C语言中,数组始终按引用传递,即,如果您修改作为参数传递给函数的数组,则不仅要在函数上下文中进行全局更改,而且要这样做。话虽这么说,但也可以说在C数组中总是按值传递,因为我们只是传递第一个元素的地址,该地址被复制到被调用者堆栈的堆栈中。但是,在两种情况下,答案都是误导的。
baibo 2014年

1
@bobbogo:这不是打包,只是没有插入免费填充。该结构的取向仅仅是其任何成员,所有这些都对准1的最大对齐
R.,GitHub的停止帮助ICE

49

你要

typedef char type24[3];

C类型声明很奇怪。如果要声明该类型的变量,则将类型精确地放置在变量名的位置。


33

R ..的答案

但是,这可能是一个非常糟糕的主意,因为结果类型是数组类型,但是使用它的用户不会看到它是数组类型。如果用作函数参数,它将通过引用而不是通过值传递,并且它的sizeof将是错误的。

没有看到它是数组的用户很可能会写这样的东西(失败):

#include <stdio.h>

typedef int twoInts[2];

void print(twoInts *twoIntsPtr);
void intermediate (twoInts twoIntsAppearsByValue);

int main () {
    twoInts a;
    a[0] = 0;
    a[1] = 1;
    print(&a);
    intermediate(a);
    return 0;
}
void intermediate(twoInts b) {
    print(&b);
}

void print(twoInts *c){
    printf("%d\n%d\n", (*c)[0], (*c)[1]);
}

它将编译并显示以下警告:

In function intermediate’:
warning: passing argument 1 of print from incompatible pointer type [enabled by default]
    print(&b);
     ^
note: expected int (*)[2]’ but argument is of type int **’
    void print(twoInts *twoIntsPtr);
         ^

并产生以下输出:

0
1
-453308976
32767

13

数组不能通过C中的值作为函数参数传递。

您可以将数组放入结构中:

typedef struct type24 {
    char byte[3];
} type24;

然后按值传递该值,但当然使用起来不太方便:x.byte[0]代替x[0]

您的函数type24_to_int32(char value[3])实际上是通过指针传递的,而不是通过值传递的。它与完全等效type24_to_int32(char *value),并且3被忽略。

如果您乐于通过指针传递,则可以坚持使用数组并执行以下操作:

type24_to_int32(const type24 *value);

这将传递一个指向数组的指针,而不是指向第一个元素的指针,因此您可以将其用作:

(*value)[0]

我不确定这真的有好处,因为如果您不小心写value[1]了,就会发生一些愚蠢的事情。


2
我认为可以通过在decay某处提及该术语来改善此答案(也许可以指出,返回数组的情况更糟-根本不起作用)。
Frerich Raabe 2015年

9

要将数组类型正确地用作函数参数或模板参数,请构造一个结构而不是typedef,然后将一个添加operator[]到该结构中,以便可以像这样使数组保持类似的功能:

typedef struct type24 {
  char& operator[](int i) { return byte[i]; }
  char byte[3];
} type24;

type24 x;
x[2] = 'r';
char c = x[2];

14
这是一个C问题,而不是C ++。无论是char&也不operator[]是存在于C.事物
迈克尔·莫里斯

3

这是一个简短的示例,说明为什么typedef数组可能会令人困惑地不一致。其他答案提供了一种解决方法。

#include <stdio.h>
typedef char type24[3];

int func(type24 a) {
        type24 b;
        printf("sizeof(a) is %zu\n",sizeof(a));
        printf("sizeof(b) is %zu\n",sizeof(b));
        return 0;
}

int main(void) {
        type24 a;
        return func(a);
}

这产生输出

sizeof(a) is 8
sizeof(b) is 3

因为type24作为参数是指针。(在C语言中,数组始终作为指针传递。)幸好,gcc8编译器默认会发出警告。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.