Массив фиксированной длины 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]).

Ответ 1

В typedef будет

typedef char type24[3];

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

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

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

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

Ответ 2

Вы хотите

typedef char type24[3];

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

Ответ 3

Из R.. 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

Ответ 4

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

Ответ 5

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

Ответ 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);
}

Это производит вывод

sizeof(a) is 8
sizeof(b) is 3

потому что type24 в качестве параметра является указателем. (В C массивы всегда передаются как указатели.) К счастью, компилятор gcc8 выдаст предупреждение по умолчанию.