typedef массив фиксированной длины - PullRequest
188 голосов
/ 24 декабря 2010

Мне нужно определить 24-битный тип данных. Я использую char[3] для представления типа. Могу ли я набрать определение char[3] до type24? Я попробовал это в примере кода. Я положил typedef char[3] type24; в моем заголовочном файле. Компилятор не жаловался на это. Но когда я определил функцию void foo(type24 val) {} в моем C-файле, он пожаловался. Я хотел бы иметь возможность определять функции, такие как type24_to_int32(type24 val) вместо type24_to_int32(char value[3]).

Ответы [ 5 ]

279 голосов
/ 24 декабря 2010

typedef будет

typedef char type24[3];

Однако, это, вероятно, очень плохая идея, потому что результирующий тип является типом массива, но пользователи этого не увидят, что это тип массива.Если он используется в качестве аргумента функции, он будет передан по ссылке, а не по значению, и sizeof для него будет неправильным.

Лучшим решением будет

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

Возможно, вы также захотите использовать unsigned char вместо char, поскольку последний имеет подпись, определяемую реализацией.

41 голосов
/ 24 декабря 2010

Вы хотите, чтобы

typedef char type24[3];

Объявления типа C выглядели странно.Вы помещаете тип точно в то место, куда будет идти имя переменной, если вы объявляли переменную этого типа.

27 голосов
/ 04 июня 2014

От ответа 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
11 голосов
/ 13 марта 2015

Чтобы правильно использовать тип массива в качестве аргумента функции или параметра шаблона, создайте структуру вместо 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];
11 голосов
/ 24 декабря 2010

Массивы не могут быть переданы в качестве параметров функции по значению в 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], тогда произойдет что-то глупое.

...