web-dev-qa-db-fra.com

#define vs const en Objective-C

Je suis nouveau dans Objective-C et j'ai quelques questions à propos de const et de la directive de prétraitement #define.

Tout d’abord, j’ai trouvé qu’il n’était pas possible de définir le type de la constante à l’aide de #define. Pourquoi donc?

Deuxièmement, y a-t-il des avantages à utiliser l’un par rapport à l’autre?

Enfin, quelle voie est la plus efficace et/ou la plus sûre?

81
ObjectiveCoder

Tout d’abord, j’ai trouvé qu’il n’était pas possible de définir le type de la constante à l’aide de #define, pourquoi?

Pourquoi est quoi? Ce n'est pas vrai:

#define MY_INT_CONSTANT ((int) 12345)

Deuxièmement, y a-t-il des avantages à utiliser l’un par rapport à l’autre?

Oui. #define définit une macro qui est remplacée même avant le début de la compilation. const ne fait que modifier une variable de sorte que le compilateur signalera une erreur si vous essayez de la modifier. Il y a des contextes dans lesquels vous pouvez utiliser un #define mais vous ne pouvez pas utiliser un const (même si j'ai du mal à en trouver un en utilisant le dernier cri). En théorie, un const prend de la place dans l'exécutable et nécessite une référence à la mémoire, mais en pratique cela n'a pas d'importance et peut être optimisé par le compilateur.

consts sont beaucoup plus conviviaux pour le compilateur et le débogueur que #defines. Dans la plupart des cas, c’est le point primordial que vous devez prendre en compte lorsque vous décidez lequel vous souhaitez utiliser.

Je viens de penser à un contexte dans lequel vous pouvez utiliser #define mais pas const. Si vous avez une constante que vous souhaitez utiliser dans beaucoup de .c fichiers, avec un #define vous le collez dans un en-tête. Avec un const, vous devez avoir une définition dans un fichier C et

// in a C file
const int MY_INT_CONST = 12345;

// in a header
extern const int MY_INT_CONST;

dans un en-tête. MY_INT_CONST ne peut pas être utilisé comme taille d’un tableau à portée statique ou globale dans n’importe quel fichier C sauf celui dans lequel il est défini.

Cependant, pour les constantes de nombre entier, vous pouvez utiliser un enum. En fait, c’est ce que Apple fait presque toujours. Cela présente tous les avantages des deux #defines et consts mais ne fonctionne que pour les constantes entières.

// In a header
enum
{
    MY_INT_CONST = 12345,
};

Enfin, quelle voie est la plus efficace et/ou la plus sûre?

#define est plus efficace en théorie bien que, comme je l’ai dit, les compilateurs modernes garantissent probablement qu’il ya peu de différence. #define est plus sécurisé dans la mesure où c'est toujours une erreur du compilateur d'essayer de l'assigner

#define FOO 5

// ....

FOO = 6;   // Always a syntax error

consts peut être amené à être assigné bien que le compilateur puisse émettre des avertissements:

const int FOO = 5;

// ...

(int) FOO = 6;     // Can make this compile

En fonction de la plate-forme, l'affectation peut toujours échouer au moment de l'exécution si la constante est placée dans un segment en lecture seule et que son comportement est officiellement indéfini conformément à la norme C.

Personnellement, pour les constantes entières, j'utilise toujours enums pour les constantes d'autres types, j'utilise const sauf si j'ai une très bonne raison de ne pas le faire.

106
JeremyP

A partir d'un codeur C:

Un const est simplement une variable dont le contenu ne peut pas être modifié.

#define name value, cependant, est une commande de préprocesseur qui remplace toutes les instances de name par value.

Par exemple, si vous #define defTest 5, toutes les occurrences de defTest dans votre code seront remplacées par 5 lorsque vous compilez.

16
MegaNairda

Il est important de comprendre la différence entre les instructions #define et const qui ne visent pas les mêmes choses.

const

const est utilisé pour générer un objet du type demandé qui, une fois initialisé, sera constant. Cela signifie que c'est un objet dans la mémoire du programme et peut être utilisé en lecture seule. L'objet est généré à chaque lancement du programme.

#define

#define est utilisé afin de faciliter la lisibilité du code et les modifications futures. Lorsque vous utilisez une définition, vous masquez uniquement une valeur derrière un nom. Ainsi, lorsque vous travaillez avec un rectangle, vous pouvez définir la largeur et la hauteur avec les valeurs correspondantes. Ensuite, dans le code, il sera plus facile à lire car au lieu de chiffres, il y aura des noms.

Si plus tard vous décidez de changer la valeur de la largeur, il vous suffira de la changer dans la définition plutôt que dans une recherche/remplacement ennuyeux et dangereux dans tout votre fichier. Lors de la compilation, le préprocesseur remplacera tout le nom défini par les valeurs du code. Par conséquent, il n'y a pas de temps perdu à les utiliser.

10
fBourgeois

En plus des commentaires des autres peuples, des erreurs d’utilisation de #define sont notoirement difficiles à déboguer car le pré-processeur les récupère avant le compilateur.

7
Ed Heal

Puisque les directives du pré-processeur sont mal vues, je suggère d’utiliser un const. Vous ne pouvez pas spécifier un type avec un pré-processeur car une directive de pré-processeur est résolue avant la compilation. Eh bien, vous pouvez, mais quelque chose comme:

#define DEFINE_INT(name,value) const int name = value;

et l'utiliser comme

DEFINE_INT(x,42) 

qui serait vu par le compilateur comme

const int x = 42;

Tout d’abord, j’ai trouvé qu’il n’était pas possible de définir le type de la constante à l’aide de #define, pourquoi?

Vous pouvez voir mon premier extrait.

Deuxièmement, y a-t-il des avantages à utiliser l’un par rapport à l’autre?

Avoir généralement une directive const au lieu d'une directive pré-processeur aide au débogage, pas autant dans ce cas (mais le fait toujours).

Enfin, quelle voie est la plus efficace et/ou la plus sûre?

Les deux sont aussi efficaces. Je dirais que la macro peut potentiellement être plus sûre, car elle ne peut pas être changée pendant l'exécution, alors qu'une variable le pourrait.

2
Luchian Grigore

J'ai déjà utilisé #define pour créer davantage de méthodes à partir d'une méthode, comme si j'avais quelque chose comme.

 // This method takes up to 4 numbers, we don't care what the method does with these numbers.
 void doSomeCalculationWithMultipleNumbers:(NSNumber *)num1 Number2:(NSNumber *)num2 Number3:(NSNumber *)num23 Number3:(NSNumber *)num3;

Mais je veux aussi une méthode qui ne prend que 3 chiffres et 2 chiffres, alors au lieu d’écrire deux nouvelles méthodes, je vais utiliser le même en utilisant le #define, comme ça.

 #define doCalculationWithFourNumbers(num1, num2, num3, num4) \
         doSomeCalculationWithMultipleNumbers((num1), (num2), (num3), (num4))

 #define doCalculationWithThreeNumbers(num1, num2, num3) \
         doSomeCalculationWithMultipleNumbers((num1), (num2), (num3), nil)

 #define doCalculationWithTwoNumbers(num1, num2) \
         doSomeCalculationWithMultipleNumbers((num1), (num2), nil, nil)

Je pense que c’est une bonne chose à faire. Je sais que vous pouvez passer directement à la méthode et ne mettre que zéro dans les espaces que vous ne voulez pas, mais si vous construisez une bibliothèque, c’est très utile. Aussi c'est comment

     NSLocalizedString(<#key#>, <#comment#>)
     NSLocalizedStringFromTable(<#key#>, <#tbl#>, <#comment#>)
     NSLocalizedStringFromTableInBundle(<#key#>, <#tbl#>, <#bundle#>, <#comment#>)

sont fait.

Alors que je ne crois pas que vous puissiez faire cela avec des constantes. Mais les constantes ont des avantages par rapport à #define car vous ne pouvez pas spécifier de type avec #define car il s’agit d’une directive de préprocesseur qui est résolue avant la compilation, et si vous obtenez une erreur avec #define, ils seront plus difficiles à déboguer. des constantes. Les deux présentent des avantages et des inconvénients, mais je dirais que tout dépend du programmeur que vous avez choisi. J'ai écrit une bibliothèque avec les deux en utilisant #define pour faire ce que j'ai montré et des constantes pour déclarer des variables constantes sur lesquelles je dois spécifier un type.

1
Popeye