Les plus utiles faite C-macros (dans GCC, aussi C99)?
Ce C macro est à votre avis est le plus utile? J'ai trouvé le suivant, que j'utilise pour faire du vecteur de l'arithmétique dans C:
#define v3_op_v3(x, op, y, z) {z[0]=x[0] op y[0]; \
z[1]=x[1] op y[1]; \
z[2]=x[2] op y[2];}
Il fonctionne comme ça:
v3_op_v3(vectorA, +, vectorB, vectorC);
v3_op_v3(vectorE, *, vectorF, vectorJ);
...
- Et vous n'êtes pas la mise en œuvre de la norme formes de vecteur de multiplication ici (pas de produit scalaire, produit vectoriel, ni tenseur de produit).
- Composant-sage de multiplication a ses utilise, mais les dimensions de la limite imposée par la macro rend-il pas utile.
- Ceci est destiné à être utilisé dans les zones où la limite dimensionnelle est strictement imposée par la nature même de la zone d'application. Comme dans les graphiques 3D, par exemple.
- Mais, supposons que le nombre de dimensions dans l'univers change, le code de rupture - c'est le genre de vision à court terme qui ont conduit au problème Y2K.
- Ouais... comme cette célèbre citation de Xerox manuel. L'un des avantages de déclarer PI comme une constante nommée, c'est qu'il vous permet de modifier le code dans le cas où la valeur de Pi changements.
- Produits vectoriels? Avez-vous oublié C est trop?
- De référence pour cette citation de Xerox FORTRAN manuel concernant les pi: en.wikiquote.org/wiki/Fortran
Vous devez vous connecter pour publier un commentaire.
pour chaque boucle en C99:
sizeof
-avec-forloop façon. Je soupçonne un mieux à double contrôle de toutes les actions dans C 🙂keep
variable, et pourquoi neforeach
étendre à un imbriquéefor
boucle?break
travail (et mon code a été brisé. J'ai pensé que j'ai copié à partir d'une réponse différente de moi, mais apparemment, je n'étais pas assez réveillé :p. J'ai corrigé, merci de vérifier)Et, bien sûr, diverses MIN, MAX, ABS, etc.
Remarque, d'ailleurs, qu'aucun des ci-dessus peut être mis en œuvre par une fonction en C.
P. S. j'aurais sans doute la-dessus
IMPLIES
macro comme l'un des plus utiles. Son but principal est de faciliter l'écriture de plus élégant et lisible affirmations, comme dansdo...while(0)
technique), mais il y a encore de multiples problèmes liés à l'évaluation que vous avez vraiment ne peut pas réparer.SWAPINT(*xp, *yp)
maintenant besoin de vérifierxp != yp
premier. Ces jours-ci je ne vois pas beaucoup de point en ajoutant un peu maladroite cas de bord afin de (peut-être) sauver un registre et/ou 4 octets de la pile.if (condition) SWAP(a, b, int); else /* something */;
avec ma version et avec les vôtres.IMPLIES
est vraiment sympa.v
à tousn
éléments du tableaud
.ZERO
utiliseSET
d'accorder de la valeur0
à tousn
éléments du tableaud
.ARRAY_SET
etARRAY_ZERO
pour être cohérent avecARRAY_SIZE
? Quand j'ai vuSET
, j'ai été en quelque sorte d'attendre que peut-être un peu spécifique à une valeur ou quelque chose.SET
etZERO
avec une macro n'est pas une bonne idée en tout cas. Mais à l'adresse de votre point de vue: le ci-dessusARRAY_SIZE
macro est destiné à être utilisé avec les tableaux uniquement (pas avec les pointeurs), tandis queSET
etZERO
ne sont pas liés à des tableaux, ils peuvent travailler avec des pointeurs ainsi. Pour continuer à suivre cette convention, le nomARRAY_SET
dans ce contexte aurait plus de sens avec la définition suivante:#define ARRAY_SET(a) SET(a, ARRAY_SIZE(a))
. De même pourARRAY_ZERO
.IMPLIES
quelqu'un peut-il m'expliquer? Ce qui est fait avec elle? Pourquoi voudriez-vous affirmer que la matrice a 0 ou négatif de la longueur OU elle n'est pas NULLE? (assert(!(n > 0) || array != NULL)
)n
est positif, alorsarray
pointeur ne peut pas être null. Dans tous les autres cas, nous ne se soucient pas ce quearray
est".n
négatif? Pourquoi ne pasassert(n > 0 && array != NULL)
? Je ne peux pas penser quand il serait OK pour avoir une longueur négative. Peut-être que ce n'était pas le meilleur exemple pour démontrerIMPLIES
?n == 0
(c'est à dire "pas de tableau passé"). Je ne veux pas vraiment à permettren < 0
, mais par souci de simplicité, je l'ai traitéen < 0
de la même manière quen == 0
(c'est à dire de négatifn
signifie aussi"no array passed"). In my code I'd actually make a point of using an *unsigned* type for
n, which would eliminate the issue of negative
n` de la considération. À la signature du type le plus approprié de l'assertion seraitassert(n >= 0 && IMPLIES(n > 0, array != NULL))
.n > 0
ici. Je veux permettre àn == 0
ainsi. Et sin == 0
, je ne veux pas imposer des exigences surarray
. C'est ce queIMPLIES
m'aide à atteindre.Le point clé avec C macros est de les utiliser correctement. Dans mon esprit il y a trois catégories (sans tenir compte de l'aide juste pour donner des noms descriptifs pour les constantes)
Dans le premier cas, la macro s'vivre dans votre programme (généralement un fichier) de sorte que vous pouvez utiliser des macros comme celui que vous avez posté, qui n'est pas protégé contre la double évaluation des paramètres et utilise
{...};
(potentiellement dangereux!).Dans le second cas (et encore plus dans le troisième), vous devez être extrêmement attention à ce que vos macros se comportent correctement, comme si elles étaient réelles C constructions.
La macro que vous avez posté de GCC (min et max) est un exemple de cela, ils utilisent les variables globales
_a
et_b
pour éviter le risque de double évaluation (comme dansmax(x++,y++)
) (bien, ils utilisent des extensions de GCC, mais le concept est le même).J'aime utiliser des macros où il contribue à rendre les choses plus claires, mais elles sont un outil pointu! Probablement que c'est ce qui leur a donné une mauvaise réputation, je pense qu'ils sont un outil très utile et C aurait été beaucoup plus pauvres si ils n'étaient pas présents.
Je vois d'autres ont fourni des exemples de point 2 (macros comme des fonctions), permettez-moi de donner un exemple de création d'un nouveau C construction: la machine à états Finis. (J'ai déjà posté ceci sur mais je n'arrive pas à être en mesure de le trouver)
que vous utilisez cette manière:
Vous pouvez ajouter une variation sur ce thème pour vous faire une idée de la FSM dont vous avez besoin.
Quelqu'un peut ne pas aimer cet exemple, mais je trouve qu'il est parfait pour montrer comment de simples macros peuvent rendre votre code plus lisible et expressive.
Si vous avez besoin de définir des données à de multiples reprises dans des contextes différents, les macros peuvent vous aider à éviter d'avoir à réinscrire la même chose plusieurs fois.
Par exemple, disons que vous souhaitez définir une énumération de couleurs et un enum-à-fonction de chaîne, plutôt que de lister toutes les couleurs à deux fois, vous pouvez créer un fichier de couleurs (couleurs.def):
Vous pouvez maintenant c ton fichier, vous pouvez définir votre enum et de votre chaîne de fonctions de conversion:
Noter que l'absence d'une virgule entre
"%s::%s(%d)"
etformat
est délibéré. Il affiche une chaîne formatée avec l'emplacement de la source précédée. Je travaille dans les systèmes temps-réel embarqués si souvent j'ai également inclure un horodateur dans la sortie ainsi.#define TRACE (format, ...) ((void)0)
à éviter les pièges commeif(cond) TRACE(...)
?if(x) TRACE("y = %d", y );
permettrait de résoudre àif(x);
qui n'aura aucun effet.;
n'était pas une instruction valide, mais ce n'est pas un problème pour GCC. affirmer.h semble toujours utiliser#define assert(ignore)((void) 0)
bien.Boucle Foreach pour GCC, spécifiquement C99 avec GNU Extensions. Fonctionne avec des chaînes et des tableaux. Des tableaux alloués dynamiquement peuvent être utilisées par casting pour un pointeur sur un tableau, et ensuite déréférencement les.
Ce code a été testé pour fonctionner avec GCC, la cour et le Bruit sur GNU/Linux.
Expressions Lambda (GCC seulement)
Vous éviter quelques erreurs de comptage
Quelqu'un d'autre a mentionné container_of(), mais ne pas fournir une explication pour ce très pratique en macro. Disons que vous avez une structure qui ressemble à ceci:
Maintenant, si nous avons un pointeur vers b, nous pouvons utiliser container_of() pour obtenir un pointeur vers chose dans un type de coffre-fort de la mode:
Ceci est utile dans la création de structures de données abstraites. Par exemple, plutôt que de prendre l'approche de la file d'attente.h faut pour créer des choses comme SLIST (des tonnes de fou macros pour chaque opération), vous pouvez maintenant écrire un slist de mise en œuvre qui ressemble à quelque chose comme ceci:
Qui n'est pas fou le code de macro. Il donnera de bons compilateur de ligne de chiffres sur les erreurs et les œuvres de nice avec le débogueur. Il est aussi assez typesafe, sauf pour les cas où les structures d'utiliser plusieurs types (par exemple, si nous avons permis struct couleur dans l'exemple ci-dessous pour être sur plus de listes liées que juste le couleurs un).
Les utilisateurs peuvent maintenant utiliser votre bibliothèque comme ceci:
C'est à partir du noyau linux (gcc spécifique):
Un autre manquant d'autres réponses:
LSB
évoque(x) & 1
.J'aime aussi celui-ci:
Et comment vous les macros-haters faire juste à virgule flottante comparaisons?
Juste le standard:
mais il n'y a rien de trop spiffy là.
#define REQUIRE_ARRAY(T, X) (void)(sizeof (((char(*)(T(*)[]))0)(&(X))))
REQUIRE_ARRAY2
pour un tableau à 2 dimensions, par exemple:#define REQUIRE_ARRAY2(T, X) (void)(sizeof (((char(*)(T(*)[*][*]))0)(&(X))))
#define IS_ARRAY(a) ((void *)&a == (void *)a)
fonctionne comme un exécution de test pour savoir si quelque chose est un tableau ou un pointeur (sauf si le pointeur pointe vers lui-même, ce qui peut se produire dans le cadre d'une circulaire à structure liée, mais qui est un peu rare).Trouver la plus proche de 32 bits entier non signé qui est plus grand que x. Je l'utilise pour le double de la taille des tableaux (c'est à dire la ligne des hautes eaux).
__builtin_clz
et un seul quart de travail?Pack octets,mots,dword en mots,dword et qwords:
Parenthesizing arguments, il est toujours une bonne pratique pour éviter les effets secondaires sur l'expansion.
typedef unsigned __int64 ULONGLONG;
aussi multi-type Minimum et Maximum comme ça
a >? b
Vérifier si une variable point x n'est Pas Un Nombre:
inline
.inline
), il suffit d'utiliser la C99isnan( )
macro définie dans<math.h>
.Un (de très peu) que j'utilise régulièrement est une macro pour déclarer un argument ou d'une variable inutilisée. Le plus compatible avec la solution ce n'est (à mon humble avis) varie en fonction du compilateur.
C'est génial:
Et je l'utilise comme:
1+
de l'allocation d'un octet supplémentaire pour chaque allocation?malloc()
ou liées à la fonction. Il faut du temps pour type, et la seule fois où il n'est rien si vous avez oublié de#include <stdlib.h>
. Si je fais ça, je préfère avoir le diagnostic que d'avoir des trucs probablement continuer à travailler.NEW
—semble assez clair pour moi, il peut allouer de la mémoire. Aussi, le casting est nécessaire pour le C++, qui ne sera pas convertir implicitement un void * vers un autre type.new
au lieu de cela, et de ne jamais utiliser les macros de ce genre.new
n'est probablement pas un bon plan.n
par la taille de ce type? Avez-vous peur que quelqu'un pourrait passern
de zéro? Que faire si ils passent une valeur négative?Le VRAI et le FAUX semble être populaire.
if (var == TRUE)
trop souvent et de refuser de les utiliser.