Quelle est la différence entre l'utilisation de CGFloat et de float?

169

J'ai tendance à utiliser CGFloat partout, mais je me demande si j'obtiens un «coup de performance» insensé avec cela. CGFloat semble être quelque chose de "plus lourd" que le flotteur, non? À quels moments dois-je utiliser CGFloat, et qu'est-ce qui fait vraiment la différence?


la source

Réponses:

193

Comme l'a dit @weichsel, CGFloat n'est qu'un typedef pour l'un floatou l' autre double. Vous pouvez le voir par vous-même en double-cliquant sur "CGFloat" dans Xcode - il passera à l'en-tête CGBase.h où le typedef est défini. La même approche est également utilisée pour NSInteger et NSUInteger.

Ces types ont été introduits pour faciliter l'écriture de code qui fonctionne à la fois sur 32 bits et 64 bits sans modification. Cependant, si tout ce dont vous avez besoin est de la floatprécision dans votre propre code, vous pouvez toujours l'utiliser floatsi vous le souhaitez - cela réduira quelque peu votre empreinte mémoire. Il en va de même pour les valeurs entières.

Je vous suggère d'investir le temps modeste nécessaire pour rendre votre application 64 bits propre et d'essayer de l'exécuter en tant que telle, car la plupart des Mac ont maintenant des processeurs 64 bits et Snow Leopard est entièrement 64 bits, y compris le noyau et les applications utilisateur. Le guide de transition 64 bits d' Apple pour Cocoa est une ressource utile.

Quinn Taylor
la source
Je pense que je comprends maintenant. Mais sur l'iPhone, cela n'a pas beaucoup d'importance, non?
4
Sur l'iPhone tel que nous le connaissons, non. Cependant, il est toujours sage d'utiliser un code à l'épreuve du temps, ce qui faciliterait la réutilisation en toute sécurité du même code pour OS X.
Quinn Taylor
donc vous dites, en gros, n'utilisez JAMAIS un float ou un double directement puisque vous seriez lié à l'architecture du processeur (et je pensais que les JVM rapides avaient été résolus il y a des années :)). Alors, quels primitifs sont sûrs? int?
Dan Rosenstark
9
Je n'ai jamais dit de ne JAMAIS utiliser directement une primitive. Il y a des moments où les primitives directes peuvent être problématiques, par exemple si une variable peut être utilisée pour stocker des données qui pourraient déborder, comme sur 64 bits. En général, l'utilisation de typedefs dépendants de l'architecture est plus sûre, car le code est moins susceptible d'exploser sur une architecture différente. Cependant, parfois, l'utilisation d'un type 32 bits peut être totalement sûre et vous faire économiser de la mémoire. La taille des primitives peut être moins problématique dans une JVM, mais Obj-C et C sont compilés, et le mélange de bibliothèques 32 et 64 bits et de code est en effet problématique.
Quinn Taylor le
1
@QuinnTaylor pouvez-vous fournir un exemple pratique de la façon dont float déborderait alors que CGFloat ne le ferait pas? Float et CGFloat ont un nombre fini de bits. Vous pouvez déborder les deux en ayant besoin de stocker plus de bits qu'ils ne peuvent en contenir.
Pwner
76

CGFloat est un float régulier sur les systèmes 32 bits et un double sur les systèmes 64 bits

typedef float CGFloat;// 32-bit
typedef double CGFloat;// 64-bit

Vous n'obtiendrez donc aucune pénalité de performance.

Thomas Zoechling
la source
3
Eh bien, vous utilisez deux fois plus de mémoire, si vous vous inquiétez de la mémoire.
Tyler
8
Seulement sur 64 bits, cependant.
Quinn Taylor
13
Correct, iPhone OS est 32 bits. Si vous y réfléchissez, l'iPhone ne pousse pas la limitation de 4 Go de RAM de 32 bits, ni n'utilise un processeur Intel (pour lequel 64 bits est plus rapide que 32 bits). De plus, il utilise Modern Runtime (par opposition à Legacy Runtime de 32 bits sur le bureau - recherchez ces termes si vous êtes curieux) afin qu'il puisse faire pratiquement tout ce que OS X 64 bits peut faire. Peut-être qu'un jour nous verrons un appareil fonctionnant sous iPhone OS et 64 bits, mais il n'y en a actuellement aucun.
Quinn Taylor
23
Entrez: l'iPhone 5S
dgund
7
5S est maintenant en 64 bits, la dernière fois que je suis entré à la conférence (Londres), ils ont dit que la façon dont ils exécutaient des applications 32 bits sur ios7 était d'initier un autre pool de cache partagé en mémoire, ce qui peut entraîner l'utilisation de plus de mémoire dans l'ensemble. il vaut donc la peine de tout convertir jusqu'à 64 bits. (sauf si vous souhaitez toujours prendre en charge 5.1+ ou 6.0+)
phil88530
2

Comme d'autres l'ont dit, CGFloat est un flottant sur les systèmes 32 bits et un double sur les systèmes 64 bits. Cependant, la décision de le faire a été héritée d'OS X, où elle a été prise en fonction des caractéristiques de performance des premiers processeurs PowerPC. En d'autres termes, vous ne devriez pas penser que float est pour les processeurs 32 bits et que le double est pour les processeurs 64 bits. (Je pense que les processeurs ARM d'Apple étaient capables de traiter les doubles bien avant qu'ils ne passent à 64 bits.) Le principal impact de l'utilisation des doubles est qu'ils utilisent deux fois la mémoire et peuvent donc être plus lents si vous effectuez de nombreuses opérations en virgule flottante. .

user3259383
la source
2

Objectif c

À partir du code source de la Fondation, dans CoreGraphics ' CGBase.h:

/* Definition of `CGFLOAT_TYPE', `CGFLOAT_IS_DOUBLE', `CGFLOAT_MIN', and
   `CGFLOAT_MAX'. */

#if defined(__LP64__) && __LP64__
# define CGFLOAT_TYPE double
# define CGFLOAT_IS_DOUBLE 1
# define CGFLOAT_MIN DBL_MIN
# define CGFLOAT_MAX DBL_MAX
#else
# define CGFLOAT_TYPE float
# define CGFLOAT_IS_DOUBLE 0
# define CGFLOAT_MIN FLT_MIN
# define CGFLOAT_MAX FLT_MAX
#endif

/* Definition of the `CGFloat' type and `CGFLOAT_DEFINED'. */

typedef CGFLOAT_TYPE CGFloat;
#define CGFLOAT_DEFINED 1

Copyright (c) 2000-2011 Apple Inc.

Cela consiste essentiellement à:

#if defined(__LP64__) && __LP64__
typedef double CGFloat;
#else
typedef float CGFloat;
#endif

__LP64__indique si l'architecture actuelle * est 64 bits.

Notez que les systèmes 32 bits peuvent toujours utiliser le 64 bits double, cela prend juste plus de temps processeur, donc CoreGraphics le fait à des fins d'optimisation et non de compatibilité. Si vous n'êtes pas préoccupé par les performances mais que vous êtes préoccupé par la précision, utilisez simplement double.

Rapide

Dans Swift, CGFloatest un structwrapper autour Floatdes architectures 32 bits ou Double64 bits (vous pouvez le détecter au moment de l'exécution ou de la compilation avec CGFloat.NativeType)

À partir du code source CoreGraphics, dansCGFloat.swift.gyb :

public struct CGFloat {
#if arch(i386) || arch(arm)
  /// The native type used to store the CGFloat, which is Float on
  /// 32-bit architectures and Double on 64-bit architectures.
  public typealias NativeType = Float
#elseif arch(x86_64) || arch(arm64)
  /// The native type used to store the CGFloat, which is Float on
  /// 32-bit architectures and Double on 64-bit architectures.
  public typealias NativeType = Double
#endif

* Plus précisément, longs et pointeurs, d'où le LP. Voir aussi: http://www.unix.org/version2/whatsnew/lp64_wp.html

Ben Leggiero
la source
1

il suffit de mentionner que - janvier 2020 Xcode 11.3 / iOS13

Swift 5

À partir du code source CoreGraphics

public struct CGFloat {
    /// The native type used to store the CGFloat, which is Float on
    /// 32-bit architectures and Double on 64-bit architectures.
    public typealias NativeType = Double
Boyan Jakimov
la source