【问题标题】:typedef fixed length arraytypedef 固定长度数组
【发布时间】: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])

【问题讨论】:

    标签: c arrays gcc typedef


    【解决方案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
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-05-18
          • 1970-01-01
          • 2019-02-28
          • 2020-08-31
          • 2011-02-16
          • 2020-03-11
          相关资源
          最近更新 更多