Ogni C programmatore può determinare il numero di elementi in una matrice con questa macro noto:affidabile determinare il numero di elementi in un array
#define NUM_ELEMS(a) (sizeof(a)/sizeof 0[a])
Qui è un tipico caso d'uso:
int numbers[] = {2, 3, 5, 7, 11, 13, 17, 19};
printf("%lu\n", NUM_ELEMS(numbers)); // 8, as expected
Tuttavia, nulla impedisce al programmatore di passare accidentalmente un puntatore invece di un array:
int * pointer = numbers;
printf("%lu\n", NUM_ELEMS(pointer));
Sul mio sistema, questo stampa 2, perché apparentemente, un puntatore è due volte più grande di un intero. Ho pensato come impedire il programmatore dal passaggio di un puntatore per errore, e ho trovato una soluzione:
#define NUM_ELEMS(a) (assert((void*)&(a) == (void*)(a)), (sizeof(a)/sizeof 0[a]))
Ciò funziona perché un puntatore a una matrice ha lo stesso valore di un puntatore al suo primo elemento. Se invece si passa un puntatore, il puntatore verrà confrontato con un puntatore a se stesso, che è quasi sempre falso. (L'unica eccezione è un puntatore nullo ricorsivo, cioè, un puntatore vuoto che punta a se stesso posso vivere con questo..)
accidentalmente passando un puntatore invece di un array ora genera un errore in fase di esecuzione:
Assertion `(void*)&(pointer) == (void*)(pointer)' failed.
Bello! Ora ho un paio di domande:
È il mio utilizzo della
assert
come operando sinistro dello Standard in vigore espressione virgola C? Cioè, lo standard mi consente di usareassert
come espressione? Scusa se questa è una domanda stupida :)Il controllo può essere eseguito in qualche modo in fase di compilazione?
Il compilatore My C ritiene che
int b[NUM_ELEMS(a)];
sia un VLA. Un modo per convincerlo del contrario?Sono il primo a pensarci? Se è così, quante vergini posso aspettarmi di aspettarmi in paradiso? :)
Come per la parte (4), piuttosto sicuro che sia * non * 72. Penso che t hat è un valore riservato per qualcos'altro ... –
Non intendi 'sizeof a [0]'? –
Ogni programmatore reale sa che tenere traccia delle dimensioni degli array è il loro problema, non i compilatori e che i trucchi per "calcolarlo" sono di utilità strettamente limitata perché tali informazioni vengono conservate solo nell'ambito.Se vuoi che il compilatore si occupi di questo per te, usa un linguaggio più intelligente. Voglio dire, devi solo andare in C++ e usare 'std :: vector' o (con C++ 11)' std :: array', quindi non è un grosso cambiamento. – dmckee