IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage C++ Discussion :

méthode versus #define


Sujet :

Langage C++

  1. #1
    Membre émérite
    Avatar de ChPr
    Homme Profil pro
    Inscrit en
    Septembre 2005
    Messages
    2 122
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 79
    Localisation : France, Val d'Oise (Île de France)

    Informations forums :
    Inscription : Septembre 2005
    Messages : 2 122
    Par défaut méthode versus #define
    Bonsoir à toutes et à tous,

    Quels sont les avantages/inconvénients relatifs de ces deux manières d'obtenir un résultat (le code n'est ici qu'un exemple) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    #define DEGREES_MINUTES_SECONDS_TO_DECIMAL_DEGREES(deg,min,sec) (deg) >= 0 ? ((float)(deg)+(float)(min)*0.0166666667+(float)(sec)*0.0002777778) : ((float)(deg)-(float)(min)*0.0166666667-(float)(sec)*0.0002777778)
     
    float dmsTOdd(float deg, float min, float sec) {
      return (deg) >= 0 ? ((float)(deg) + (float)(min) * 0.0166666667 + (float)(sec) * 0.0002777778) : ((float)(deg) - (float)(min) * 0.0166666667 - (float)(sec) * 0.0002777778);
    }
    Merci pour vos renseignements.

    Pierre

  2. #2
    Expert confirmé
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Décembre 2015
    Messages
    1 599
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Décembre 2015
    Messages : 1 599
    Par défaut
    Bonjour,

    Partons de ton exemple :
    combien vaut : 180+DEGREES_MINUTES_SECONDS_TO_DECIMAL_DEGREES(10,0,0) ? réponse 10.0 !!
    combien vaut : int dg=90; DEGREES_MINUTES_SECONDS_TO_DECIMAL_DEGREES(++dg,0,0) ? réponse 92 !!

    Si on ajoute inline avant la fonction : inline float dmsTOdd(float deg, float min, float sec) elle sera implémentée avec un compacité au moins équivalente à la macro.

    Donc avantage à la macro pour un traitement du type fonction : NEANT

  3. #3
    Membre émérite
    Avatar de ChPr
    Homme Profil pro
    Inscrit en
    Septembre 2005
    Messages
    2 122
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 79
    Localisation : France, Val d'Oise (Île de France)

    Informations forums :
    Inscription : Septembre 2005
    Messages : 2 122
    Par défaut
    J'avoue n'avoir strictement rien compris.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    combien vaut : 180+DEGREES_MINUTES_SECONDS_TO_DECIMAL_DEGREES(10,0,0) ? réponse 10.0 !!
    veut donc dire qu'on ne peut pas ajouter une macro et un nombre ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    combien vaut : int dg=90; DEGREES_MINUTES_SECONDS_TO_DECIMAL_DEGREES(++dg,0,0) ? réponse 92 !!
    Ici, cela veut dire que dg est incrémenté deux fois ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Si on ajoute inline avant la fonction : inline float dmsTOdd(float deg, float min, float sec) elle sera implémentée avec un compacité au moins équivalente à la macro.
    Je te crois.

    Mais de là en tirer la conclusion que tu fais, alors là, je suis complètement perdu.

    Cordialement.

    Pierre

  4. #4
    Expert confirmé
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Décembre 2015
    Messages
    1 599
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Décembre 2015
    Messages : 1 599
    Par défaut
    Une macro c'est en fait un remplacement d'un texte, ça peut avoir des effets indésirables.
    180+DEGREES_MINUTES_SECONDS_TO_DECIMAL_DEGREES(10,0,0) devient en remplaçant
    180+(10) >= 0 ? ((float)(10)+(float)(0)*0.0166666667+(float)(0)*0.0002777778) : ((float)(10)-(float)(0)*0.0166666667-(float)(0)*0.0002777778), donc le 180 s'ajoute ici au test. La syntaxe est trompeuse!
    int dg=90; DEGREES_MINUTES_SECONDS_TO_DECIMAL_DEGREES(++dg,0,0) devient 180+(++dg) >= 0 ? ((float)(++dg)+(float)(0)*0.0166666667+(float)(0)*0.0002777778) : ((float)(++dg)-(float)(0)*0.0166666667-(float)(0)*0.0002777778).
    Les macros présentent donc un piège. Les fonctions inline ont la capacité de mieux vérifier les types et d'éviter ces effets de bord.
    Autrefois c'était un moyen d'optimiser du code, depuis il y a les fonctions inline et les template qui sont capable de faire au moins aussi bien et plus surement.

  5. #5
    Membre émérite
    Avatar de ChPr
    Homme Profil pro
    Inscrit en
    Septembre 2005
    Messages
    2 122
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 79
    Localisation : France, Val d'Oise (Île de France)

    Informations forums :
    Inscription : Septembre 2005
    Messages : 2 122
    Par défaut
    Ah, et bien là, je comprends beaucoup mieux. Merci "dalfab".

    Cordialement.

    Pierre

  6. #6
    Expert confirmé
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 772
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 772
    Par défaut
    Et ouais, tu as fais l'erreur de ne pas surparenthèser ta macro : c'est direct la baffe/ le point qui tue


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    #define DEGREES_MINUTES_SECONDS_TO_DECIMAL_DEGREES(deg,min,sec) ((deg >= 0)? ((float)(deg)+(float)(min)*0.0166666667+(float)(sec)*0.0002777778): ((float)(deg)-(float)(min)*0.0166666667-(float)(sec)*0.0002777778))
    Et ensuite tu as eu la deuxième réponse classique anti-macro : Comme tu es bête, il faut que tu fasses attention parce que ta macro tu peux la mettre partout/ l'utiliser à mauvais escient. Et même le compilateur ni peut rien.

    Donc plus une macro de ce style:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    #define DEGREES_MINUTES_SECONDS_TO_DECIMAL_DEGREES(deg, min, sec, result) \
        if ((deg >= 0) { \
            result = ((float) (deg) + (float) (min) * 0.0166666667 + (float) (sec) * 0.0002777778); \
        } else { \
            result = ((float) (deg) - (float) (min) * 0.0166666667 - (float) (sec) * 0.0002777778); \
        }

  7. #7
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 202
    Par défaut
    Et encore, ca ne suffit pas.
    Cette dernière version de macro n'acceptes pas de ; après son utilisation.
    Et elle n'est pas étanche non plus à une expression en parametre faisant un effet de bord (comme un ++)
    Chaque fois qu'un parametre est utilisé, son texte est recopié.

    Une macro n'est pas du C++. ça génère du code C++, avec les morceaux de code qu'on lui donne en arguments.

    Ainsi, la macro proposée
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    #define DEGREES_MINUTES_SECONDS_TO_DECIMAL_DEGREES(d, min, sec, result) \
        if ((deg >= 0) { \
            result = ((float) (deg) + (float) (min) * 0.0166666667 + (float) (sec) * 0.0002777778); \
        } else { \
            result = ((float) (deg) - (float) (min) * 0.0166666667 - (float) (sec) * 0.0002777778); \
        }
    appelée avec DEGREES_MINUTES_SECONDS_TO_DECIMAL_DEGREES(++d, 0, 0, dms), devient (si on ajoute les espaces enlevés par le préprocesseur):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
        if ((++d >= 0) {
            dms = ((float) (++d) + (float) (0) * 0.0166666667 + (float) (0) * 0.0002777778);
        } else {
            dms = ((float) (++d) - (float) (0) * 0.0166666667 - (float) (0) * 0.0002777778);
        }
    Le ++ est appelé deux fois, les constantes numériques sont des approximations exprimées comme double (donc narrowing), il n'y a pas de static_cast, etc.

    Notons que l'expression sera plus convenable avec des constantes du bon type (vive les promotions arithmétiques).
    inline float dms_to_f(int deg, int min, int sec) { return d + (d<0?-1:1)* ( min/60.f + sec/3600.f ); }inline double dms_to_d(int deg, int min, int sec) { return d + (d<0?-1:1)* ( min/60. + sec/3600. ); }

  8. #8
    Membre émérite
    Avatar de ChPr
    Homme Profil pro
    Inscrit en
    Septembre 2005
    Messages
    2 122
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 79
    Localisation : France, Val d'Oise (Île de France)

    Informations forums :
    Inscription : Septembre 2005
    Messages : 2 122
    Par défaut
    Citation Envoyé par foetus Voir le message
    ... Comme tu es bête, il faut que tu fasses attention parce que ta macro tu peux la mettre partout/ l'utiliser à mauvais escient. ...
    Je te remercie pour ton appréciation "no limit".

    Pour autant, je précise que je n'ai fait aucune opération avec cette macro, j'ai juste demandé quels en étaient les avantages et inconvénients vis à vis d'une méthode.

    Merci aux réponses constructives.

    Cordialement.

    Pierre

  9. #9
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Salut,
    Citation Envoyé par ChPr Voir le message
    Je te remercie pour ton appréciation "no limit".

    Pierre
    Je ne crois pas qu'il faille prendre cette remarque pour une attaque personnelle, mais bien pour la réalité qu'elle insinue.

    Il ne faut pas oublier que plus de 80% de notre boulot de développeur consiste à ... utiliser des fonctionnalités qui ont été développées "par quelqu'un d'autre" (même si ce "quelqu'un d'autre, c'est parfois / souvent toi).

    Du coup, on devient de manière systématique l'utilisateur des fonctionnalités utilisées dans les algorithmes que nous développons, et, c'est bien là que se trouve tout le problème :

    On peut le dire de différentes manières, allant de "80 % des bugs trouvent leur origine entre la chaise et le clavier" à "l'utilisateur est un imbécile idiot", en passant par l'approche plus philosophique de "l'erreur est humaine"; la constatation reste fondamentalement la même : si tu laisses la possibilité à un utilisateur de faire une connerie, la loi de finagle aidant, tu peux avoir la certitude que l'utilisateur fera cette connerie à un moment ou à un autre.

    Il ne sert donc à rien de se demander SI il la fera, car on a la certitude que ce sera le cas, mais on devrait se demander QUAND il la fera. Et la réponse sera toujours la même : au pire moment qui soit.

    A partir de là, ta "condition bassement humaine" fait que tu ne vaut certainement pas "moins" que "l'utilisateur lambda", mais que tu aurais largement tord de croire que tu vaux "beaucoup mieux" que lui : tu feras -- peut-être -- moins d'erreur que l'utilisateur moyen, mais, quand tu en feras (car la loi de finagle est contre toi comme elle est contre tous les autres), elles risquent d'être beaucoup plus graves.

    Ceci étant dit : les macros remplacent "bêtement" chaque symbole défini par son équivalent en "texte représentant du code", sans effectuer la moindre vérification ni analyse du code "généré".

    Et comme les macros ont comme résultat de "cacher" le code réellement exécuté derrière un symbole, bien que le résultat soit -- peut-être -- plus facile à lire (et encore faut-il que le symbole soit bien choisi), la compréhension de ce que fait réellement le code et l'évaluation du résultat du code s'en trouve plus compliquée, vue que, après tout, on n'est pas sensé savoir par quoi le symbole est remplacé.

    Enfin, il ne faut pas oublier qu'il est "tellement facile de faire une erreur dans du code que l'on écrit", et qu'il en va de même avec les macros. Si bien que, au final, on a plus d'inconvénient à utiliser une macro qu'une fonction classique (surtout si elle peut être inlinée), sans en tirer d'avantage réel (un nom de fonction cohérent sera tout aussi "parlant" qu'un nom de symbole cohérent). Si bien que la décision finale d'utiliser les macros te revient forcément, tant que tu es maître du projet sur lequel tu travailles. Mais il n'y a finalement qu'une seule décision "logique" à prendre les concernant, qui exclut les autres possibilités
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  10. #10
    Expert confirmé
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 772
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 772
    Par défaut
    Citation Envoyé par koala01 Voir le message
    bien que le résultat soit -- peut-être -- plus facile à lire (et encore faut-il que le symbole soit bien choisi), la compréhension de ce que fait réellement le code et l'évaluation du résultat du code s'en trouve plus compliquée, vue que, après tout, on n'est pas sensé savoir par quoi le symbole est remplacé.

    Enfin, il ne faut pas oublier qu'il est "tellement facile de faire une erreur dans du code que l'on écrit", et qu'il en va de même avec les macros. Si bien que, au final, on a plus d'inconvénient à utiliser une macro qu'une fonction classique (surtout si elle peut être inlinée)
    Je me suis pris le chou avec un autre posteur récemment parce qu'il y a un cas que les macros n'ont pas encore d'équivalent en C++ moderne ou pas

    Sur des lignes de code sans initialisation, que des tests ou de la recopie. Un bloc impossible à "inliner", répétitif, et qu'on s'en fiche presque ce qu'il fait exactement.
    Le seul hic c'est que dans ce bloc, des variables sont créées (cela peut engendrer des collisions sans erreur et des variables invisibles) ou des variables doivent être créées avant.
    La solution c'est appeler la macro entre accolades (créer un bloc d'instructions rien que pour elle)
    L'autre hic, c'est qu'il ne faut pas avoir 1 erreur dans ce bloc, sinon elle est répétée X fois (<- mais c'est du code en théorie bête comme chou)
    L'autre hic, il faut éventuellement connaître la variable retour à tester après la macro
    Et enfin Libre à chacun d'avoir des appels de fonctions/ méthodes pour des cacahuètes

    Exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    #define TEST_XXX_IS_SAME \
    	unsigned char is_same = 1; \
    	 \
    	for(pos = 0; (is_same && (pos < KEY_LENGTH)); ++pos) { \
    		if (app_master_key[pos] != key_XXX[pos]) { is_same = 0; } \
    	} \
    	 \
    	if (!is_same) { \
    		is_same = 1; \
    		 \
    		for(pos = 0; (is_same && (pos < KEY_LENGTH)); ++pos) { \
    			if (app_read_key[pos] != key_XXX[pos]) { is_same = 0; } \
    		} \
    		 \
    		if (!is_same) { \
    			is_same = 1; \
    			 \
    			for(pos = 0; (is_same && (pos < KEY_LENGTH)); ++pos) { \
    				if (app_write_key[pos] != key_XXX[pos]) { is_same = 0; } \
    			} \
    			 \
    			if (!is_same) { \
    				ret = 1; \
    			} else { \
    				handler->error = GLB_ERR_HANDLER_XXX_APK2; \
    				 \
    				ret = 0; \
    			} \
    		} else { \
    			handler->error = GLB_ERR_HANDLER_XXX_APK1; \
    			 \
    			ret = 0; \
    		} \
    	} else { \
    		handler->error = GLB_ERR_HANDLER_XXX_MAK; \
    		 \
    		ret = 0; \
    	}
     
     
    #define WRITE_CARD_XXX_CONTENT \
    	/*XXX test: FILE_MAX_SIZE == (AID_LENGTH + FID_LENGTH + (3 * KEY_LENGTH));*/ \
    	unsigned char pos, key_pos; \
    	 \
    	handler->last_task = TASK_PUT_FILE_CONTENT; handler->error = GLB_ERROR_NONE; \
    	 \
    	is_finished = 0; \
    	nb_tries = 0; \
    	 \
    	/*Write AID, FID, first APK1, second APK1*/ \
    	for(pos = 0; pos < AID_LENGTH; ++pos) { handler->little_buffer[AID_LENGTH - pos - 1] = app_ID[pos]; } \
    	 \
    	handler->little_buffer[AID_LENGTH] = 01 /*file_index*/; \
    	 \
    	key_pos = AID_LENGTH + 1; \
    	 \
    	for(pos = 0; pos < KEY_LENGTH; ++pos) { handler->little_buffer[key_pos + pos] = first_app_read_key[pos]; } \
    	 \
    	key_pos += KEY_LENGTH; \
    	 \
    	for(pos = 0; pos < KEY_LENGTH; ++pos) { handler->little_buffer[key_pos + pos] = second_app_read_key[pos]; } \
    	 \
    	/*pos += key_pos;*/ \
    	 \
    	for(pos = 0; pos < KEY_LENGTH; ++pos) { handler->little_buffer[key_pos + pos] = 0x94; } \
    	 \
    	key_pos += KEY_LENGTH; \
    	 \
    	/*for(; pos < FILE_MAX_SIZE; ++pos) { handler->little_buffer[key_pos + pos] = 0x00; }*/ \
    	 \
    	do { \
    		ret = device_put_file_content(&(handler->device), NULL, NULL, 0x01, 0, FILE_MAX_SIZE, handler->little_buffer); \
    		 \
    		TEST_RETURN_TRY \
    	} while(!ret && !is_finished);

  11. #11
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 202
    Par défaut
    Et ca te parait une bonne macro?

    Je n'ai jamais rencontré une fonction dont le temps d'appel soit perceptible par rapport à son temps d'execution qui ne puisse pas être inlinée sans passer par une macro.

    Ta macro géante ne sert à rien, car elle ne prend aucun argument.
    Le code produit coûte déjà cher à exécuter: elle contrient plusieurs boucles faisant des appels de fonctions. Et tu ne veux pas en rajouter un?
    Quel avantage?

  12. #12
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Citation Envoyé par foetus Voir le message
    Et enfin Libre à chacun d'avoir des appels de fonctions/ méthodes pour des cacahuètes

    Exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    #define TEST_XXX_IS_SAME \
    	unsigned char is_same = 1; \
    	 \
    	for(pos = 0; (is_same && (pos < KEY_LENGTH)); ++pos) { \
    		if (app_master_key[pos] != key_XXX[pos]) { is_same = 0; } \
    	} \
    	 \
    	if (!is_same) { \
    		is_same = 1; \
    		 \
    		for(pos = 0; (is_same && (pos < KEY_LENGTH)); ++pos) { \
    			if (app_read_key[pos] != key_XXX[pos]) { is_same = 0; } \
    		} \
    		 \
    		if (!is_same) { \
    			is_same = 1; \
    			 \
    			for(pos = 0; (is_same && (pos < KEY_LENGTH)); ++pos) { \
    				if (app_write_key[pos] != key_XXX[pos]) { is_same = 0; } \
    			} \
    			 \
    			if (!is_same) { \
    				ret = 1; \
    			} else { \
    				handler->error = GLB_ERR_HANDLER_XXX_APK2; \
    				 \
    				ret = 0; \
    			} \
    		} else { \
    			handler->error = GLB_ERR_HANDLER_XXX_APK1; \
    			 \
    			ret = 0; \
    		} \
    	} else { \
    		handler->error = GLB_ERR_HANDLER_XXX_MAK; \
    		 \
    		ret = 0; \
    	}
     
     
    #define WRITE_CARD_XXX_CONTENT \
    	/*XXX test: FILE_MAX_SIZE == (AID_LENGTH + FID_LENGTH + (3 * KEY_LENGTH));*/ \
    	unsigned char pos, key_pos; \
    	 \
    	handler->last_task = TASK_PUT_FILE_CONTENT; handler->error = GLB_ERROR_NONE; \
    	 \
    	is_finished = 0; \
    	nb_tries = 0; \
    	 \
    	/*Write AID, FID, first APK1, second APK1*/ \
    	for(pos = 0; pos < AID_LENGTH; ++pos) { handler->little_buffer[AID_LENGTH - pos - 1] = app_ID[pos]; } \
    	 \
    	handler->little_buffer[AID_LENGTH] = 01 /*file_index*/; \
    	 \
    	key_pos = AID_LENGTH + 1; \
    	 \
    	for(pos = 0; pos < KEY_LENGTH; ++pos) { handler->little_buffer[key_pos + pos] = first_app_read_key[pos]; } \
    	 \
    	key_pos += KEY_LENGTH; \
    	 \
    	for(pos = 0; pos < KEY_LENGTH; ++pos) { handler->little_buffer[key_pos + pos] = second_app_read_key[pos]; } \
    	 \
    	/*pos += key_pos;*/ \
    	 \
    	for(pos = 0; pos < KEY_LENGTH; ++pos) { handler->little_buffer[key_pos + pos] = 0x94; } \
    	 \
    	key_pos += KEY_LENGTH; \
    	 \
    	/*for(; pos < FILE_MAX_SIZE; ++pos) { handler->little_buffer[key_pos + pos] = 0x00; }*/ \
    	 \
    	do { \
    		ret = device_put_file_content(&(handler->device), NULL, NULL, 0x01, 0, FILE_MAX_SIZE, handler->little_buffer); \
    		 \
    		TEST_RETURN_TRY \
    	} while(!ret && !is_finished);
    Parce que tu crois vraiment qu'il y a un intérêt quelconque à inliner ce genre de code

    Le cout d'un appel de fonction classique sera peanuts par rapport au temps d'exécution des différentes boucles, d'autant plus que certaines sont imbriquées (je parle essentiellement de la macro WRITE_CARD_XXX_CONTENT). Quant à l'autre macro (TEST_XXX_IS_SAME), il n'y aura qu'avec une valeur de KEY_LENGTH (dont on ignore tout) très base qu'il y aura effectivement intérêt à l'inlining, et encore, à condition que la clé ne soit pas trouvée, car, autrement, on part de toutes façons à la fête à la saucisse!

    Quoi qu'il en soit, avant d'accepter de telles macros dans le code, j'insisterai fortement pour qu'on me montre des benchmarks me prouvant que j'ai tord de préférer ma fonction "classique"
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  13. #13
    Expert confirmé
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 772
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 772
    Par défaut
    L'idée de ces macros, c'est de factoriser du code répétitif (sans allocation/ sans destruction) en 1 macro (et donc si tu modifies la macro tu modifies X endroits en même temps)

    Un autre exemple que j'ai, c'est pour une application IHM: rendre un label cliquable+"hover" ou pas (c'est au moins 4 lignes).
    Mais ces quelques lignes, tu les trouves un peu partout et des fois plusieurs fois dans une méthode/ fonction (surtout lorsque tu n'as pas de tableau et tu y vas élément par élément)

    L'autre truc aussi de la macro, c'est de ne pas surcharger les classes (en C++) ou les interfaces (en C) avec si peu (qui va faire 1 méthode pour 1 triple-test, ou une écriture de 100 octets (KEY_LENGTH == 32))
    Parce que je l'avoue mes macros sont à part dans un fichier "macros.h".

    Et enfin, faire des méthodes/ fonctions cela peut être pénible: une signature avec 4-5 (ou plus) paramètres (exemple TEST_XXX_IS_SAME) et un retour à créer.
    Parce que la macro permet de créer des variables ou d'en utiliser déjà existantes (même du recyclage de variables dans une méthode/ fonction).
    Justement ternel a pointé le fait que je n'ai pas de paramètres. Parce que je recycle/ utilise des variables (ret)

    Comme je l'ai dit, cela peut poser des problèmes de collisions de noms et /ou de créer des variables invisibles. Pour éviter cela on peut l'appeler entre accolades.

    Et tout cela évidement, c'est une macro: donc si on la colle dans une condition de if ou dans du code sous-parenthésés, elles vont [peut-être] faire n'importe quoi.
    Mais à un moment, c'est au développeur de réfléchir un peu à ce qu'il code et ne pas s'en remettre à 100% au compilateur ou autre.


    Édit: Je demande même si mes macros évitent des "include" dans les entêtes . Par exemple, si je centre un TButton en fonction d'un TLabel ou TXXX, je n'ai besoin que de include "windows.h" à l'implémentation et non pas à la définition.
    Parce que, avec C++ Builder Xe, on ne peut pas implémenter ces fonctions/ méthodes inline dans le fichier .cXX (que dans les entêtes)

  14. #14
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Citation Envoyé par foetus Voir le message
    L'idée de ces macros, c'est de factoriser du code répétitif (sans allocation/ sans destruction) en 1 macro (et donc si tu modifies la macro tu modifies X endroits en même temps)
    Ca, je l'ai bien compris, merci...

    Mais tu peux arriver exactement au même résultat avec une fonction classique, et la macro n'apporte en définitive... que la certitude de l'inining.

    Alors, prouves moi
    1. qu'il n'y a pas moyen d'obtenir l'inining autrement (entre autres, en modifiant les réglages du compilateur à ce sujet)
    2. que l'inlining est indispensable en termes de performances (bench à l'appuis)


    et j'envisagerai peut être de changer d'avis

    Mais, en attendant, je campe sur mes positions
    Un autre exemple que j'ai, c'est pour une application IHM: rendre un label cliquable+"hover" ou pas (c'est au moins 4 lignes).
    Mais ces quelques lignes, tu les trouves un peu partout et des fois plusieurs fois dans une méthode/ fonction (surtout lorsque tu n'as pas de tableau et tu y vas élément par élément)
    Avec la conception qui va bien, ce n'est pas un problème...

    L'autre truc aussi de la macro, c'est de ne pas surcharger les classes (en C++) ou les interfaces (en C) avec si peu (qui va faire 1 méthode pour 1 triple-test, ou une écriture de 100 octets (KEY_LENGTH == 32))
    Parce que je l'avoue mes macros sont à part dans un fichier "macros.h".
    Quel intérêt l'interface est justement l'ensemble des services auxquels on estime devoir être en mesure d'accédeer depuis l'extérieur d'un objet. Si c'est un service "publique", place ta fonction dans l'accessibilité publique; si c'est un "service privé" (uniquement intéressant pour les fonctions membres de la classes), tapes le dans l'accessibilité privée, et on n'en parle plus

    Et enfin, faire des méthodes/ fonctions cela peut être pénible: une signature avec 4-5 (ou plus) paramètres (exemple TEST_XXX_IS_SAME) et un retour à créer.
    Parce que la macro permet de créer des variables ou d'en utiliser déjà existantes (même du recyclage de variables dans une méthode/ fonction).
    Justement ternel a pointé le fait que je n'ai pas de paramètres. Parce que je recycle/ utilise des variables (ret)
    Et tu peux faire exactement pareil avec les fonctions, surtout si tu introduit un peu de programmation générique
    Comme je l'ai dit, cela peut poser des problèmes de collisions de noms et /ou de créer des variables invisibles. Pour éviter cela on peut l'appeler entre accolades.
    Mais... quelle est la différence avec les fonctions !!!

    Et tout cela évidement, c'est une macro: donc si on la colle dans une condition de if ou dans du code sous-parenthésés, elles vont [peut-être] faire n'importe quoi.
    Mais à un moment, c'est au développeur de réfléchir un peu à ce qu'il code et ne pas s'en remettre à 100% au compilateur ou autre.
    On est bien d'accord sur le fait que c'est au développeur de réfléchir un peu à ce qu'il fait... Mais les fonctions évitent quand même bien des soucis
    Édit: Je demande même si mes macros évitent des "include" dans les entêtes . Par exemple, si je centre un TButton en fonction d'un TLabel ou TXXX, je n'ai besoin que de include "windows.h" à l'implémentation et non pas à la définition.
    Parce que, avec C++ Builder Xe, on ne peut pas implémenter ces fonctions/ méthodes inline dans le fichier .cXX (que dans les entêtes)
    Ah, mais quand tu auras tout dit...

    J'ai personnellement abandonné C++ builder quand il était à sa version 5 (ou 6 ) et n'y ai plus trop regardé depuis... Mais, que penserais tu d'utiliser un IDE (et surtout une bibliothèque graphique) un peu correcte

    Car, elle a peut-être évolué depuis, mais la VCL, du moins, telle que je l'ai connue à l'époque ... bon, je ferais surement mieux de me taire
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  15. #15
    Expert confirmé
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 772
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 772
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Et tu peux faire exactement pareil avec les fonctions, surtout si tu introduit un peu de programmation générique

    Mais... quelle est la différence avec les fonctions !!!
    J'ai regardé un peu sur Internet avec tes réponses mon histoire de macro qui permet d'isoler/ réutiliser des morceaux de codes (que ce soit en C++ ou C)

    Et cela correspond à une lambda stockée/ réutilisable avec closure.

    Et effectivement en C++ on peut s'en sortir avec une classe/ foncteur éventuellement template éventuellement avec Boost , mais il faudra si nécessaire capturer l'environnement local manuellement si on ne veut pas exploser le nombre de paramètres (et donc on perd la simplicité et l'opacité de la macro)

    Et l'autre truc, ces morceaux de code ne sont pas [forcément] reliés à une classe. Il sont fortement indépendants.

  16. #16
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Par défaut
    Pas relié à une classe => Fonction libre, ou classe foncteur spécifique (éventuellement obtenue à partir d'une lambda)
    Réutiliser des variables de types différent => Fonction template
    Je ne vois rien dans ta macro qui justifie son existence à mon sens.

    Il m'arrive régulièrement d'utiliser des macros, mais uniquement pour des choses que les fonctions ne peuvent pas faire, en particulier ce que permettent # et ##.
    Exemple récent :
    Pour faire un bench, j'ai créé une fonction template avec deux éléments de variations que je veux tester :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    template<class Stats, class Fct>
    void measure(string const &title, string const & text, Fct fct)
    { /*...*/ }
    Et tant qu'à faire, autant que le titre du test reprenne les paramètres de celui-ci. Donc, là, oui, j'emballe cette fonction dans une macro :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    #define MEASURE(STAT, FCT) measure<STAT>(#STAT " " #FCT, text, [](STAT &s, string const &t, size_t start, size_t end){FCT(s, t, start, end);})
    Et dans mon main, c'est cette macro que j'utilise:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
        MEASURE(StatsHomegeneous, reference);
        MEASURE(StatsHomegeneous, countWordsString);
    Du coup, je suis certain que mon affichage en sortie est correct, et j'évite de répéter mes paramètres de test. Mais s'il n'y avait pas eu ce #STAT ou ce #FCT, je n'aurais clairement pas écrit de macro.
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. C# versus Java
    Par laffreuxthomas dans le forum C#
    Réponses: 368
    Dernier message: 30/03/2019, 22h59
  2. Erreur "Application Defined" avec la méthode CopyFromRecordset
    Par Milyshyn76 dans le forum VB 6 et antérieur
    Réponses: 2
    Dernier message: 16/11/2016, 11h41
  3. Procédural dans l'objet (méthodes versus fonctions)
    Par Jimalexp dans le forum Langages de programmation
    Réponses: 7
    Dernier message: 23/01/2009, 14h32
  4. Probleme d'impression avec la méthode TForm->Print()
    Par Kid Icarus dans le forum C++Builder
    Réponses: 13
    Dernier message: 31/07/2002, 14h26
  5. Cryptage en C selon la méthode de césat
    Par shenron dans le forum C
    Réponses: 2
    Dernier message: 31/05/2002, 08h22

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo