web-dev-qa-db-fra.com

Macro de longueur de tableau commune pour C?

J'ai vu plusieurs macros pour la longueur du tableau flottant autour:

De cette 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))

Et de Visual Studio _countof :

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

Ce que j'aimerais savoir, c'est:

  1. Quelle est la différence entre ceux qui utilisent array[0] et *array?
  2. Pourquoi devrait-on préférer l'un ou l'autre?
  3. Diffèrent-ils en C++?
32
Matt Joiner

Voici une meilleure version C (du projet Chromium de Google):

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

Il améliore la version array[0] Ou *array En utilisant 0[array], Ce qui équivaut à array[0] Sur des tableaux simples, mais ne parviendra pas à compiler si array se trouve être un type C++ qui surcharge operator[]().

La division provoque une opération de division par zéro (qui doit être interceptée au moment de la compilation car il s'agit d'une expression constante au moment de la compilation) pour de nombreuses situations (mais pas toutes) où un pointeur est passé en tant que paramètre array.

Voir Y a-t-il une fonction standard en C qui retournerait la longueur d'un tableau? pour plus de détails.

Il existe une meilleure option pour le code C++. Voir Compile time sizeof_array sans utiliser de macro pour plus de détails.

60
Michael Burr
  1. Quelle est la différence entre ceux qui utilisent tableau [0] et * tableau?
  2. Pourquoi devrait-on préférer l'un ou l'autre?
  3. Diffèrent-ils en C++?

(1) Aucune différence en C. Aucune différence pour un tableau brut réel en C++.

(2) Aucune raison technique de préférer l'un ou l'autre, mais les débutants peuvent être déroutés par la déréférence du pointeur.

(3) En C++, vous n'utilisez normalement pas la macro, car elle est très dangereuse. Si vous passez un pointeur au lieu d'un tableau brut réel, le code sera compilé mais donnera un résultat incorrect. Donc, en C++, vous devriez/devriez plutôt utiliser un modèle de fonction, comme…

#include <stddef.h>

typedef ptrdiff_t Size;

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

Cela n'accepte que le tableau brut réel comme argument.

Cela fait partie d'une triade de fonctions startOf, endOf et countOf qu'il est très pratique de définir afin qu'elles puissent être appliquées à la fois aux tableaux bruts et aux conteneurs de bibliothèque standard. Autant que je sache, cette triade a été identifiée pour la première fois par Dietmar Kuehl. En C++ 0x startOf et endOf seront très probablement disponibles en tant que std::begin et std::end.

Santé et hth.,

15

1) Rien, la valeur d'un tableau est un pointeur sur son premier élément. Donc * tableau == tableau [0]
2) Préférence personnelle
3) Non

Notez que cette macro ne fonctionnera pas si elle est appelée dans une fonction où le tableau est passé en paramètre dans la fonction. Cela est dû au fait que l'objet tableau a transmis des "désintégrations" dans un pointeur plutôt qu'une copie complète.

3
SiegeX