2010-12-11 22 views
27

Ho visto diverse macro per lunghezza dell'array galleggianti intorno:Macro di lunghezza dell'array comune per C?

Da this question:

  • #define length(array) (sizeof(array)/sizeof(*(array)))
  • #define ARRAY_LENGTH(array) (sizeof((array))/sizeof((array)[0]))
  • #define SIZE(array, type) (sizeof(array)/(sizeof(type))

e Visual Studio _countof:

#define _countof(_Array) (sizeof(_Array)/sizeof(_Array[0])) 

Quello che mi piacerebbe sapere è:

  1. Qual è la differenza tra quelli che utilizzano array[0] e *array?
  2. Perché dovrebbe essere preferibile?
  3. Differiscono in C++?

risposta

51

Ecco una versione migliore C (dal progetto Chromium di Google):

#define COUNT_OF(x) ((sizeof(x)/sizeof(0[x]))/((size_t)(!(sizeof(x) % sizeof(0[x]))))) 

Migliora sulla versione array[0] o *array utilizzando 0[array], che equivale a array[0] su array semplici, ma non riuscirà a compilare se array sembra essere un tipo C++ che sovraccarica operator[]().

La divisione causa un'operazione di divisione per zero (che dovrebbe essere rilevata in fase di compilazione poiché è un'espressione costante in fase di compilazione) per molte (ma non tutte) situazioni in cui un puntatore viene passato come parametro array.

Vedere Is there a standard function in C that would return the length of an array? per ulteriori dettagli.

C'è un'opzione migliore per il codice C++. Vedi Compile time sizeof_array without using a macro per i dettagli.

+8

Questo è incredibilmente criptico solo per evitare di essere usato in modo errato in C++, considerando che qualcos'altro dovrebbe essere usato in C++ comunque. –

+1

Hai ragione che non dovrebbe essere usato in C++, ma il bit che fornisce un po 'di sicurezza specifica per C++ non è davvero troppo criptico (è solo l'indicizzazione insolita). La parte veramente criptica protegge da alcuni tipi di uso improprio in C che in realtà è piuttosto difficile da evitare (e la macro non protegge nemmeno perfettamente da questo abuso). L'uso improprio di cui si occupa (passando un puntatore invece di un argomento dell'array) si verifica abbastanza spesso che si paga per avere la complessità. Avvolto in una macro, la complessità non è un problema (e questa macro è meno criptica di molti che ho incontrato). –

+0

Che tipo di diavolo è '0 [x]'? Ce la puoi fare? –

3

1) Nulla, il valore di un array è un puntatore al suo primo elemento. Così * array == array [0]
2) Preferenza Personale
3) n

Si noti che questa macro non funzionerà se chiamato all'interno di una funzione in cui la matrice viene passato come parametro nella funzione. Questo perché l'oggetto array ha passato "decadimenti" in un puntatore piuttosto che in una copia profonda.

+0

Sì, può funzionare efficacemente come 'sizeof (void *)/sizeof (array [0])', che - nella realtà contemporanea - significa 8, 4, 2, 1 o 0.;) In ogni caso - nulla può ti aiuta in tale funzione in fase di compilazione - non puoi mai sapere chi lo chiama e con quale grandezza un array. –

15
  1. Qual è la differenza tra quelli che utilizzano array [0] e * array?
  2. Perché dovrebbe essere preferibile?
  3. Differiscono in C++?

(1) Nessuna differenza in C. Nessuna differenza per un array raw reale in C++.

(2) Nessun motivo tecnico per preferire l'uno o l'altro, ma i neofiti potrebbero essere confusi dal dereferenziamento del puntatore.

(3) In C++ normalmente non si utilizza la macro, perché è molto pericolosa. Se passi un puntatore invece di un vero array raw, il codice verrà compilato ma restituirà un risultato errato. Quindi in C++ dovresti/dovresti usare un modello di funzione, come & hellip;

#include <stddef.h> 

typedef ptrdiff_t Size; 

template< class Type, Size n > 
Size countOf(Type (&)[n]) { return n; } 

Questo accetta solo l'array raw effettivo come argomento.

Fa parte di una triade di funzioni startOf, endOf e countOf che è molto comodo per definire in modo che possano essere applicati ad entrambe le matrici prime e contenitori della libreria standard. Per quanto ne so, questa triade fu identificata per la prima volta da Dietmar Kuehl. In C++ 0x startOf e endOf saranno probabilmente disponibili come std::begin e std::end.

Cheers & hth.,

+2

+1: interessante! C'è un motivo per usare '' piuttosto che ''? –

+0

Non che io possa pensare; e posso pensare a diversi motivi per preferire . –

+1

Per quel poco che vale, ecco la mia opinione sul ragionamento '' vs. '' (nota: preferisco la variazione C vecchio stile anch'io): http://stackoverflow.com/questions/2118422/scope-of -c-libraries-in-cxh-vs-cx/2118718 # 2118718 –