typedef array a lunghezza fissa


210

Devo definire un tipo di dati a 24 bit. Sto usando char[3]per rappresentare il tipo. Posso char[3]scrivere a type24? L'ho provato in un esempio di codice. Ho inserito il typedef char[3] type24;mio file di intestazione. Il compilatore non si è lamentato. Ma quando ho definito una funzione void foo(type24 val) {}nel mio file C, mi sono lamentato. Vorrei poter definire funzioni come type24_to_int32(type24 val)invece di type24_to_int32(char value[3]).

Risposte:


320

Il typedef sarebbe

typedef char type24[3];

Tuttavia, questa è probabilmente una pessima idea, perché il tipo risultante è un tipo di array, ma gli utenti non vedranno che si tratta di un tipo di array. Se usato come argomento di funzione, verrà passato per riferimento, non per valore, e sizeofquindi sarà errato.

Una soluzione migliore sarebbe

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

Probabilmente vuoi anche usare unsigned charinvece di char, poiché quest'ultimo ha una firma definita dall'implementazione.


10
Esiste un bel documento che descrive i casi angolari coinvolti nel passaggio di matrici dattiloscritte come parametri? Ad esempio, se una funzione prende un parametro type24 foo, quali sarebbero le dimensioni, tipi, e significati di foo, *foo, **foo, &foo, e &&foo? I significati e la legalità di tali espressioni sono cambiati nel corso degli anni?
supercat

4
Probabilmente vale la pena menzionare l'avvertenza di impaccamento della struttura, poiché un tipo di dati a 24 bit potrebbe essere inteso per mappare a qualcosa con semantica di impacchettamento diversamente definita come i dati di immagine RGB.
sh1,

2
@ sh1: su tutti gli ABI del mondo reale di cui sono a conoscenza - anche quelli in cui l'accesso disallineato è molto costoso - le strutture non ottengono requisiti di allineamento più forti di quelli che i loro membri avrebbero senza la struttura. Ovviamente OP o chiunque utilizzi questo approccio dovrebbe verificare il mio reclamo se ha importanza per il comportamento e la portabilità del loro programma.
R .. GitHub FERMA AIUTANDO ICE

4
@R .. Una parte di questo è fuorviante: in C, le matrici vengono sempre passate per riferimento, ovvero, se si modifica l'array passato come argomento a una funzione, lo si fa a livello globale, non solo nel contesto della funzione. Detto questo, si potrebbe anche sostenere che in C le matrici vengono sempre passate per valore poiché passiamo semplicemente l'indirizzo del primo elemento, che viene copiato nella pila sulla pila chiamata. In entrambi i casi, tuttavia, la risposta è fuorviante.
baibo,

1
@bobbogo: questo non è imballaggio, è solo il non inserimento di imbottiture gratuite. L'allineamento della struttura è solo il massimo allineamento di uno qualsiasi dei suoi membri, che hanno tutti l'allineamento 1.
R .. GitHub STOP HELPING ICE

49

Tu vuoi

typedef char type24[3];

Le dichiarazioni di tipo C sono strane in questo modo. Metti il ​​tipo esattamente dove andrebbe il nome della variabile se dichiarassi una variabile di quel tipo.


33

Dalla risposta di R .. :

Tuttavia, questa è probabilmente una pessima idea, perché il tipo risultante è un tipo di array, ma gli utenti non vedranno che si tratta di un tipo di array. Se usato come argomento di funzione, verrà passato per riferimento, non per valore, e la dimensione di esso sarà quindi errata.

Gli utenti che non vedono che si tratta di un array molto probabilmente scriveranno qualcosa del genere (che fallisce):

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

Si compilerà con i seguenti avvisi:

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

E produce il seguente output:

0
1
-453308976
32767

13

Le matrici non possono essere passate come parametri di funzione per valore in C.

È possibile inserire l'array in una struttura:

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

e poi lo passa per valore, ma ovviamente è meno comodo da usare: x.byte[0]invece di x[0].

La tua funzione type24_to_int32(char value[3])passa effettivamente dal puntatore, non dal valore. È esattamente equivalente a type24_to_int32(char *value), e 3viene ignorato.

Se sei felice che passa dal puntatore, si potrebbe rimanere con l'array e fare:

type24_to_int32(const type24 *value);

Questo passerà un puntatore all'array, non un puntatore al primo elemento, quindi lo usi come:

(*value)[0]

Non sono sicuro che sia davvero un guadagno, dal momento che se scrivi per sbaglio value[1]allora succede qualcosa di stupido.


2
Penso che questa risposta potrebbe essere migliorata citando il termine decayda qualche parte (e forse sottolineando che la situazione è peggiore per il ritorno di array - che non funziona affatto).
Frerich Raabe, il

9

Per utilizzare correttamente il tipo di array come argomento di funzione o parametro modello, crea una struttura anziché un typedef, quindi aggiungi una operator[]struttura allo scopo di mantenere l'array come funzionalità in questo modo:

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

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

14
Questa è una domanda C, non C ++. Né char&, né operator[]sono cose che esistono in C.
Michael Morris

3

Ecco un breve esempio del motivo per cui l'array typedef può essere incoerente in modo confuso. Le altre risposte forniscono una soluzione 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);
}

Questo produce l'output

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

perché type24 come parametro è un puntatore. (In C, gli array vengono sempre passati come puntatori.) Il compilatore gcc8 emetterà un avviso di default, per fortuna.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.