Was ist der Unterschied zwischen CGFloat und Float?

169

Ich neige dazu, CGFloat überall zu verwenden, aber ich frage mich, ob ich damit einen sinnlosen "Performance-Hit" bekomme. CGFloat scheint etwas "schwerer" als Float zu sein, oder? An welchen Stellen sollte ich CGFloat verwenden und was macht wirklich den Unterschied?


quelle

Antworten:

193

Wie @weichsel sagte, ist CGFloat nur ein typedef für entweder floatoder double. Sie können sich selbst davon überzeugen, indem Sie bei Xcode mit dem Befehl auf "CGFloat" doppelklicken. Es wird zum CGBase.h-Header gesprungen, in dem das typedef definiert ist. Der gleiche Ansatz wird auch für NSInteger und NSUInteger verwendet.

Diese Typen wurden eingeführt, um das Schreiben von Code zu vereinfachen, der sowohl mit 32-Bit als auch mit 64-Bit ohne Änderungen funktioniert. Wenn Sie jedoch nur floatPräzision in Ihrem eigenen Code benötigen , können Sie diese weiterhin verwenden, floatwenn Sie möchten - dies reduziert Ihren Speicherbedarf etwas. Gleiches gilt für ganzzahlige Werte.

Ich schlage vor, Sie investieren die bescheidene Zeit, die erforderlich ist, um Ihre App 64-Bit sauber zu machen, und versuchen, sie als solche auszuführen, da die meisten Macs jetzt 64-Bit-CPUs haben und Snow Leopard vollständig 64-Bit ist, einschließlich des Kernels und der Benutzeranwendungen. Apples 64-Bit-Übergangshandbuch für Kakao ist eine nützliche Ressource.

Quinn Taylor
quelle
Ich glaube, ich verstehe es jetzt. Aber auf dem iPhone scheint es nicht viel zu bedeuten, oder?
4
Auf dem iPhone, wie wir es kennen, nein. Es ist jedoch immer ratsam, zukunftssicheren Code zu verwenden, und dies würde es einfacher machen, denselben Code sicher für OS X wiederzuverwenden.
Quinn Taylor
Sie sagen also im Grunde, NIEMALS direkt ein Float oder Double verwenden, da Sie seitdem an die Prozessorarchitektur gebunden wären (und ich dachte, schnelle JVMs wurden vor Jahren gelöst :)). Welche Grundelemente sind also sicher? int?
Dan Rosenstark
9
Ich habe nicht gesagt, NIEMALS ein Primitiv direkt zu verwenden. Es gibt Zeiten, in denen gerade Grundelemente problematisch sein können, z. B. wenn eine Variable möglicherweise zum Speichern von Daten verwendet wird, die überlaufen könnten, z. B. bei 64-Bit. Im Allgemeinen ist die Verwendung von architekturabhängigen Typedefs sicherer, da Code in einer anderen Architektur weniger wahrscheinlich explodiert. Manchmal kann die Verwendung eines 32-Bit-Typs jedoch völlig sicher sein und Speicherplatz sparen. Die Größe von Grundelementen ist in einer JVM möglicherweise weniger problematisch, aber Obj-C und C werden kompiliert, und das Mischen von 32- und 64-Bit-Bibliotheken und -Code ist in der Tat problematisch.
Quinn Taylor
1
@QuinnTaylor Können Sie ein praktisches Beispiel dafür geben, wie Float überlaufen würde, während CGFloat dies nicht tun würde? Sowohl float als auch CGFloat haben eine endliche Anzahl von Bits. Sie können beide überlaufen lassen, indem Sie mehr Bits speichern müssen, als sie aufnehmen können.
Pwner
76

CGFloat ist ein regulärer Float auf 32-Bit-Systemen und ein Double auf 64-Bit-Systemen

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

Sie erhalten also keine Leistungseinbußen.

Thomas Zoechling
quelle
3
Nun, Sie verwenden doppelt so viel Speicher, wenn Sie sich Sorgen um den Speicher machen.
Tyler
8
Nur auf 64-Bit.
Quinn Taylor
13
Richtig, iPhone OS ist 32-Bit. Wenn Sie darüber nachdenken, drängt das iPhone weder auf die 4-GB-RAM-Beschränkung von 32-Bit, noch verwendet es einen Intel-Prozessor (für den 64-Bit schneller als 32-Bit ist). Außerdem wird Modern Runtime verwendet (im Gegensatz zu Legacy Runtime von 32-Bit auf dem Desktop - suchen Sie SO nach diesen Begriffen, wenn Sie neugierig sind), damit es im Grunde alles kann, was 64-Bit OS X kann. Vielleicht werden wir eines Tages ein Gerät sehen, auf dem das iPhone OS ausgeführt wird und das 64-Bit ist, aber derzeit gibt es keines.
Quinn Taylor
23
Geben Sie ein: das iPhone 5S
dgund
7
5S ist jetzt in 64 Bit. Als ich das letzte Mal an der Konferenz (London) teilgenommen habe, haben sie gesagt, dass die Ausführung von 32-Bit-Apps auf ios7 darin besteht, einen weiteren gemeinsam genutzten Cache-Pool im Speicher zu initiieren, was insgesamt zu mehr Speicherplatz führen kann. Es lohnt sich also auf jeden Fall, alles auf 64-Bit umzustellen. (es sei denn, Sie möchten noch 5.1+ oder 6.0+ unterstützen)
phil88530
2

Wie andere bereits gesagt haben, ist CGFloat ein Float auf 32-Bit-Systemen und ein Double auf 64-Bit-Systemen. Die Entscheidung dazu wurde jedoch von OS X übernommen, wo sie auf den Leistungsmerkmalen früherer PowerPC-CPUs beruhte. Mit anderen Worten, Sie sollten nicht denken, dass float für 32-Bit-CPUs und double für 64-Bit-CPUs gilt. (Ich glaube, Apples ARM-Prozessoren waren in der Lage, Doubles zu verarbeiten, lange bevor sie 64-Bit wurden.) Der größte Leistungseinbruch bei der Verwendung von Doubles besteht darin, dass sie den doppelten Speicher belegen und daher möglicherweise langsamer sind, wenn Sie viele Gleitkommaoperationen ausführen .

user3259383
quelle
2

Ziel c

Aus dem Foundation-Quellcode in 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.

Dies ist im Wesentlichen zu tun:

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

Wobei __LP64__angibt, ob die aktuelle Architektur * 64-Bit ist.

Beachten Sie, dass 32-Bit-Systeme weiterhin 64-Bit verwenden doublekönnen. Es dauert lediglich mehr Prozessorzeit. CoreGraphics tut dies daher zu Optimierungszwecken und nicht aus Kompatibilitätsgründen. Wenn Sie sich nicht um die Leistung, sondern um die Genauigkeit sorgen, verwenden Sie einfach double.

Schnell

In Swift gibt CGFloates einen structWrapper entweder Floatfür 32-Bit-Architekturen oder Doublefür 64-Bit -Architekturen (Sie können dies zur Laufzeit oder zur Kompilierung mit erkennen CGFloat.NativeType).

Aus dem CoreGraphics-Quellcode inCGFloat.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

* Insbesondere longs und Zeiger, daher die LP. Siehe auch: http://www.unix.org/version2/whatsnew/lp64_wp.html

Ben Leggiero
quelle
1

Erwähnen Sie einfach das - Jan, 2020 Xcode 11.3 / iOS13

Swift 5

Aus dem CoreGraphics-Quellcode

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
quelle