typedef固定长度数组

341*_*008 194 c arrays gcc typedef

我必须定义一个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]).

R..*_*R.. 288

typedef会是

typedef char type24[3];
Run Code Online (Sandbox Code Playgroud)

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

一个更好的解决方案是

typedef struct type24 { char x[3]; } type24;
Run Code Online (Sandbox Code Playgroud)

您可能也希望使用unsigned char而不是char,因为后者具有实现定义的签名.

  • 有没有什么好的文档描述了将typedef'ed数组作为参数传递所涉及的极端情况?例如,如果一个函数采用参数`type24 foo`,那么`foo`,`*foo`,`**foo`,`&foo`和`&& foo`的大小,类型和含义是什么?多年来,这些表达方式的含义和合法性是否有所改变? (9认同)
  • 可能值得一提的是结构打包警告,因为24位数据类型可能旨在映射到具有不同定义的打包语义(如RGB图像数据)的内容. (4认同)
  • @R ..其中一部分是误导性的 - 在C中,数组**总是**通过引用传递,即,如果修改作为参数传递给函数的数组,则全局执行,不仅仅是在上下文中功能.这就是说,人们也可以争辩说,在C数组中**总是**被值传递,因为我们只是传递第一个元素的地址,它被复制到被调用堆栈的堆栈上.然而,在这两种情况下,答案都是误导性的. (4认同)
  • @ sh1:在我所知道的所有现代真实世界的ABI中 - 即使是未对齐的访问非常昂贵 - 结构也没有比没有结构的成员更强的对齐要求.当然OP或使用这种方法的任何人都应该验证我的声明,如果它对他们的程序的行为和可移植性有影响. (2认同)
  • @bobbogo:你的测试有问题。`3` 是一个 `int`,并且 `sizeof(int)!=3`。 (2认同)

yst*_*sth 44

你要

typedef char type24[3];
Run Code Online (Sandbox Code Playgroud)

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

  • @CătălinaSîrbu 请参阅破译声明的从右到左规则:http://cseweb.ucsd.edu/~ricko/rt_lt.rule.html (7认同)
  • 我本来期待“typedef char[3] type24”,但看起来我错了:))。有什么解释为什么会这样吗? (2认同)

Ger*_*ger 28

来自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]);
}
Run Code Online (Sandbox Code Playgroud)

它将使用以下警告进行编译:

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);
         ^
Run Code Online (Sandbox Code Playgroud)

并产生以下输出:

0
1
-453308976
32767
Run Code Online (Sandbox Code Playgroud)


Ste*_*sop 12

数组不能按C中的值作为函数参数传递.

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

typedef struct type24 {
    char byte[3];
} type24;
Run Code Online (Sandbox Code Playgroud)

然后按值传递,但当然使用它不太方便:x.byte[0]而不是x[0].

您的函数type24_to_int32(char value[3])实际上是通过指针传递,而不是通过值.它完全相同type24_to_int32(char *value),而且3被忽略了.

如果你很高兴通过指针传递,你可以坚持使用数组并执行:

type24_to_int32(const type24 *value);
Run Code Online (Sandbox Code Playgroud)

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

(*value)[0]
Run Code Online (Sandbox Code Playgroud)

我不确定这真的是一种收获,因为如果你不小心写了,value[1]那么就会发生一些愚蠢的事情.

  • 我认为可以通过在某处提及“衰减”一词来改进这个答案(也许通过指出 *returning* 数组的情况更糟 - 这根本不起作用)。 (2认同)

Ger*_*imo 11

要正确使用数组类型作为函数参数或模板参数,请创建一个结构而不是一个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];
Run Code Online (Sandbox Code Playgroud)

  • 这是一个C问题,而不是C ++。“ char&”和“ operator []”都不是C中存在的东西。 (5认同)

小智 6

下面是一个简短的示例,说明了为什么 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);
}
Run Code Online (Sandbox Code Playgroud)

这会产生输出

sizeof(a) is 8
sizeof(b) is 3
Run Code Online (Sandbox Code Playgroud)

因为type24作为参数是一个指针。(在 C 中,数组总是作为指针传递。)幸运的是,gcc8 编译器默认会发出警告。