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&amp;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&amp;foo&amp;&amp;foo 的大小、类型和含义是什么?这些年来,任何此类表达的含义和合法性是否发生了变化? 可能值得一提的是结构打包警告,因为 24 位数据类型可能旨在映射到具有不同定义打包语义的东西,例如 RGB 图像数据。 @sh1:在我所知道的所有现代现实世界 ABI 上——即使是那些未对齐访问非常昂贵的 ABI——结构并没有比没有结构的成员具有更强的对齐要求。当然,如果这对他们的程序的行为和可移植性有影响,OP 或任何其他使用这种方法的人都应该验证我的声明。 @R.. 这一部分是误导性的 - 在 C 中,数组总是通过引用传递,即,如果您修改作为参数传递给函数的数组,您可以在全局范围内这样做,而不仅仅是在函数的上下文中。话虽如此,人们也可能会争辩说,在 C 中,数组总是按值传递,因为我们只是传递第一个元素的地址,该地址被复制到被调用者堆栈上的堆栈中。然而,在这两种情况下,答案都具有误导性。 @bobbogo:你的测试有问题。 3intsizeof(int)!=3

以上是关于typedef 固定长度数组的主要内容,如果未能解决你的问题,请参考以下文章

typedef

typedef 的使用

在程序中用typedef定义结构体

typedef见解即如何定义一个数组指针

为啥我无法完成数组类型的 typedef 名称?

SWIG:映射 typedef 的数组