typedef 固定长度数组
Posted
技术标签:
【中文标题】typedef 固定长度数组【英文标题】:typedef fixed length array 【发布时间】:2011-05-30 05:44:03 【问题描述】:我必须定义一个 24 位数据类型。我使用char[3]
来表示该类型。我可以将char[3]
键入type24
吗?我在代码示例中进行了尝试。我将typedef char[3] type24;
放在我的头文件中。编译器没有抱怨它。但是当我在我的 C 文件中定义一个函数 void foo(type24 val)
时,它确实抱怨了。我希望能够定义像 type24_to_int32(type24 val)
这样的函数,而不是 type24_to_int32(char value[3])
。
【问题讨论】:
【参考方案1】:构建了accepted answer,一个多维数组类型,即定长数组的定长数组,不能用
typedef char[M] T[N]; // wrong!
相反,可以像接受的答案一样声明和使用中间一维数组类型:
typedef char T_t[M];
typedef T_t T[N];
或者,T
可以在单个(可以说是令人困惑的)语句中声明:
typedef char T[N][M];
它定义了M
字符的N
数组类型(注意这里的顺序)。
【讨论】:
【参考方案2】:这里有一个简短的例子,说明为什么 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 编译器默认会发出警告,谢天谢地。
【讨论】:
【参考方案3】:你想要
typedef char type24[3];
C 类型声明在这种情况下很奇怪。如果要声明该类型的变量,则将类型准确地放在变量名称所在的位置。
【讨论】:
我期待typedef char[3] type24
,但看起来我错了:))。有什么解释为什么会这样吗?
@CătălinaSîrbu 请参阅用于破译声明的左右规则:cseweb.ucsd.edu/~ricko/rt_lt.rule.html【参考方案4】:
要将数组类型正确用作函数参数或模板参数,请创建一个结构而不是 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];
【讨论】:
这是一个 C 问题,而不是 C++。char&
和 operator[]
都不是 C 中存在的东西。【参考方案5】:
来自R..'s answer:
但是,这可能是一个非常糟糕的主意,因为生成的类型 是一个数组类型,但它的用户不会看到它是一个数组类型。 如果用作函数参数,它将通过引用传递,而不是通过 值,那么它的 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
【讨论】:
【参考方案6】:数组不能作为函数参数在 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]
,那么就会发生一些愚蠢的事情。
【讨论】:
我认为可以通过在某处提及decay
一词来改进这个答案(也许通过指出 returning 数组的情况更糟 - 这不起作用完全)。【参考方案7】:
typedef 是
typedef char type24[3];
但是,这可能是一个非常糟糕的主意,因为生成的类型是数组类型,但它的用户不会看到它是数组类型。如果用作函数参数,它将通过引用传递,而不是通过值传递,那么它的sizeof
将是错误的。
更好的解决方案是
typedef struct type24 char x[3]; type24;
您可能还想使用unsigned char
而不是char
,因为后者具有实现定义的签名。
【讨论】:
是否有任何好的文档描述了将 typedef 数组作为参数传递所涉及的极端情况?例如,如果函数接受参数type24 foo
,那么foo
、*foo
、**foo
、&foo
和&&foo
的大小、类型和含义是什么?这些年来,任何此类表达的含义和合法性是否发生了变化?
可能值得一提的是结构打包警告,因为 24 位数据类型可能旨在映射到具有不同定义打包语义的东西,例如 RGB 图像数据。
@sh1:在我所知道的所有现代现实世界 ABI 上——即使是那些未对齐访问非常昂贵的 ABI——结构并没有比没有结构的成员具有更强的对齐要求。当然,如果这对他们的程序的行为和可移植性有影响,OP 或任何其他使用这种方法的人都应该验证我的声明。
@R.. 这一部分是误导性的 - 在 C 中,数组总是通过引用传递,即,如果您修改作为参数传递给函数的数组,您可以在全局范围内这样做,而不仅仅是在函数的上下文中。话虽如此,人们也可能会争辩说,在 C 中,数组总是按值传递,因为我们只是传递第一个元素的地址,该地址被复制到被调用者堆栈上的堆栈中。然而,在这两种情况下,答案都具有误导性。
@bobbogo:你的测试有问题。 3
是 int
和 sizeof(int)!=3
。以上是关于typedef 固定长度数组的主要内容,如果未能解决你的问题,请参考以下文章