matriz de longitud fija typedef


210

Tengo que definir un tipo de datos de 24 bits. Estoy usando char[3]para representar el tipo. ¿Puedo escribir def char[3]a type24? Lo probé en una muestra de código. Puse typedef char[3] type24;en mi archivo de encabezado. El compilador no se quejó de ello. Pero cuando definí una función void foo(type24 val) {}en mi archivo C, se quejó. Me gustaría poder definir funciones como en type24_to_int32(type24 val)lugar de type24_to_int32(char value[3]).

Respuestas:


320

El typedef sería

typedef char type24[3];

Sin embargo, esta es probablemente una muy mala idea, porque el tipo resultante es un tipo de matriz, pero los usuarios no verán que es un tipo de matriz. Si se usa como un argumento de función, se pasará por referencia, no por valor, y sizeofentonces el error será incorrecto.

Una mejor solución sería

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

Probablemente también desee usar en unsigned charlugar de char, ya que este último tiene una firma definida por la implementación.


10
¿Hay algún buen documento que describa los casos de esquina involucrados con el paso de matrices definidas como parámetros? Por ejemplo, si una función toma un parámetro type24 foo, cuáles serían los tamaños, tipos y significados de foo, *foo, **foo, &foo, y &&foo? ¿Han cambiado los significados y la legalidad de tales expresiones a lo largo de los años?
supercat

44
Probablemente valga la pena mencionar la advertencia de estructura de empaque, ya que un tipo de datos de 24 bits podría tener la intención de mapear a algo con una semántica de empaque diferente definida como datos de imagen RGB.
sh1

2
@ sh1: Soy consciente de todas las ABI modernas del mundo real, incluso aquellas en las que el acceso desalineado es muy costoso, las estructuras no obtienen requisitos de alineación más estrictos que sus miembros sin la estructura. Por supuesto, OP o cualquier otra persona que use este enfoque debe verificar mi reclamo si va a importar el comportamiento y la portabilidad de su programa.
R .. GitHub DEJA DE AYUDAR A ICE

44
@R .. Una parte de esto es engañosa: en C, las matrices siempre se pasan por referencia, es decir, si modifica la matriz pasada como argumento a una función, lo hace globalmente, no solo en el contexto de la función. Dicho esto, también se podría argumentar que en C las matrices siempre se pasan por valor, ya que simplemente pasamos la dirección del primer elemento, que se copia en la pila en la pila llamada. En ambos casos, sin embargo, la respuesta es engañosa.
baibo

1
@bobbogo: Eso no es empacar, es solo la no inserción de relleno gratuito. La alineación de la estructura es solo la alineación máxima de cualquiera de sus miembros, todos los cuales tienen alineación 1.
R .. GitHub DEJE DE AYUDAR AL HIELO

49

Usted quiere

typedef char type24[3];

Las declaraciones de tipo C son extrañas de esa manera. Pones el tipo exactamente donde iría el nombre de la variable si declararas una variable de ese tipo.


33

De la respuesta de R .. :

Sin embargo, esta es probablemente una muy mala idea, porque el tipo resultante es un tipo de matriz, pero los usuarios no verán que es un tipo de matriz. Si se usa como un argumento de función, se pasará por referencia, no por valor, y el tamaño de este será incorrecto.

Los usuarios que no ven que es una matriz probablemente escribirán algo como esto (que falla):

#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]);
}

Se compilará con las siguientes advertencias:

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);
         ^

Y produce el siguiente resultado:

0
1
-453308976
32767

13

Las matrices no se pueden pasar como parámetros de función por valor en C.

Puede poner la matriz en una estructura:

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

y luego pasar eso por valor, pero por supuesto, es menos conveniente usarlo: en x.byte[0]lugar de x[0].

Su función en type24_to_int32(char value[3])realidad pasa por puntero, no por valor. Es exactamente equivalente a type24_to_int32(char *value), y 3se ignora.

Si estás pasando por feliz puntero, podría seguir con la matriz y hacer:

type24_to_int32(const type24 *value);

Esto pasará un puntero a matriz, no un puntero a primer elemento, por lo que lo usará como:

(*value)[0]

No estoy seguro de que sea realmente una ganancia, ya que si escribes accidentalmente, value[1]sucede algo estúpido.


2
Creo que esta respuesta podría mejorarse mencionando el término en decayalguna parte (y tal vez señalando que la situación es peor para devolver matrices, lo que no funciona en absoluto).
Frerich Raabe

9

Para usar el tipo de matriz correctamente como un argumento de función o parámetro de plantilla, haga una estructura en lugar de un typedef, luego agregue una operator[]a la estructura para que pueda mantener la funcionalidad de la matriz de la siguiente manera:

typedef struct type24 {
  char& operator[](int i) { return byte[i]; }
  char byte[3];
} type24;

type24 x;
x[2] = 'r';
char c = x[2];

14
Esta es una pregunta C, no C ++. Ni char&tampoco lo operator[]son las cosas que existen en C.
Michael Morris

3

Aquí hay un breve ejemplo de por qué typedef array puede ser confusamente inconsistente. Las otras respuestas proporcionan una solución alternativa.

#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);
}

Esto produce la salida

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

porque type24 como parámetro es un puntero. (En C, las matrices siempre se pasan como punteros). Afortunadamente, el compilador gcc8 emitirá una advertencia por defecto.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.