176

I tend to use CGFloat all over the place, but I wonder if I get a senseless "performance hit" with this. CGFloat seems to be something "heavier" than float, right? At which points should I use CGFloat, and what makes really the difference?

5 Answers5

200

As @weichsel stated, CGFloat is just a typedef for either float or double. You can see for yourself by Command-double-clicking on "CGFloat" in Xcode — it will jump to the CGBase.h header where the typedef is defined. The same approach is used for NSInteger and NSUInteger as well.

These types were introduced to make it easier to write code that works on both 32-bit and 64-bit without modification. However, if all you need is float precision within your own code, you can still use float if you like — it will reduce your memory footprint somewhat. Same goes for integer values.

I suggest you invest the modest time required to make your app 64-bit clean and try running it as such, since most Macs now have 64-bit CPUs and Snow Leopard is fully 64-bit, including the kernel and user applications. Apple's 64-bit Transition Guide for Cocoa is a useful resource.

Quinn Taylor
  • 44,553
  • 16
  • 113
  • 131
  • I think I get it now. But on the iPhone it seems to not matter much, right? –  Aug 12 '09 at 20:08
  • 4
    On the iPhone as we know it, no. However, it's always wise to future-proof code, and this would make it easier to safely reuse the same code for OS X. – Quinn Taylor Aug 12 '09 at 20:31
  • so you're saying, basically, NEVER use a float or double directly since then you'd be tied to the processor architecture (and I thought fast JVMs solved this years ago :)). So what primitives are safe? `int`? – Dan Rosenstark Jul 09 '10 at 15:21
  • 10
    I didn't say NEVER use a primitive directly. There are times that straight primitives can be problematic, such as if a variable may conceivably be used to store data which could overflow, such as on 64-bit. In general, using architecture-dependent typedefs is safer, in that code is less likely to explode on a different architecture. However, sometimes using a 32-bit type can be completely safe and save you memory. The size of primitives may be less of an issue in a JVM, but Obj-C and C are compiled, and mixing 32 and 64 bit libraries and code is indeed problematic. – Quinn Taylor Jul 09 '10 at 22:10
  • 1
    @QuinnTaylor can you provide a practical example of how float would overflow while CGFloat would not? Both float and CGFloat have a finite number of bits. You can overflow both of them by needing to store more bits than they can hold. – Pwner Feb 24 '15 at 19:55
  • One place this overflows is when using float/double as method return values like (double)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath. That will cause problems on 32-bit systems while working fine on 64-bit systems, thus being extremely hard to find/debug. The solution is to use CGFloat here. This is arguably a slightly contrived example, but a valid one. – conceptDawg Aug 28 '15 at 18:31
78

CGFloat is a regular float on 32-bit systems and a double on 64-bit systems

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

So you won't get any performance penalty.

Thomas Zoechling
  • 34,177
  • 3
  • 81
  • 112
  • 3
    Well, you use twice as much memory, if you're worried about memory. – Tyler Aug 12 '09 at 08:58
  • 13
    Correct, iPhone OS is 32-bit. If you think about it, the iPhone isn't pushing the 4GB RAM limitation of 32-bit, nor is it using an Intel processor (for which 64-bit is faster than 32-bit). Plus, it's using Modern Runtime (as opposed to Legacy Runtime of 32-bit on the desktop — wearch SO for these terms if you're curious) so it can do basically everything 64-bit OS X can. Perhaps someday we'll see a device that runs iPhone OS and is 64-bit, but currently there are none. – Quinn Taylor Aug 12 '09 at 20:35
  • 1
    You won't necessarily use "twice as much memory". In most normal situations on 64 bit architectures, you're going to align on 64 bit boundaries anyway, so if you allocated memory or define structs limited to 32 bit types, unless you personally are packing/unpacking pairs of 32 bit values into 64 bit words, you are probably going to end up with 64 bit underlying storage anyway. – Jeb Aug 30 '13 at 21:34
  • 7
    5S is now in 64 bit, last time I entered the conference (london), they said the way they run 32-bit apps on ios7 is to init another shared cache pool in memory, which can result in using more memory overall. so its def worth to convert everything up to 64-bits. (unless you want to support 5.1+ or 6.0+ still) – phil88530 Dec 30 '13 at 14:26
  • Is it safe to put a CGFloat into NSNumber: `[NSNumber numberWithFloat:myCGFloatVar]` – nr5 Sep 26 '17 at 07:50
  • You should use `[NSNumber numberWithDouble:myCGFloatVar]` because `CGFloat` is defined as `double` on 64-bit platforms. – Thomas Zoechling Sep 26 '17 at 07:55
  • Let's add that: 1. The `32 bit float` is the correct choice where ever code consistency is required. 2. But once aligned on `64 Bit CPU` it costs the same memory as if it was 64 bit (so, 32 bits are wasted). 3. While `CGFloat` allows you to use the maximum the system has to offer! – Top-Master Apr 29 '21 at 20:55
3

As others have said, CGFloat is a float on 32-bit systems and a double on 64-bit systems. However, the decision to do that was inherited from OS X, where it was made based on the performance characteristics of early PowerPC CPUs. In other words, you should not think that float is for 32-bit CPUs and double is for 64-bit CPUs. (I believe, Apple's ARM processors were able to process doubles long before they went 64-bit.) The main performance hit of using doubles is that they use twice the memory and therefore might be slower if you are doing a lot of floating point operations.

user3259383
  • 149
  • 1
  • 9
3

Objective-C

From the Foundation source code, 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.

This is essentially doing:

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

Where __LP64__ indicates whether the current architecture* is 64-bit.

Note that 32-bit systems can still use the 64-bit double, it just takes more processor time, so CoreGraphics does this for optimization purposes, not for compatibility. If you aren't concerned about performance but are concerned about accuracy, simply use double.

Swift

In Swift, CGFloat is a struct wrapper around either Float on 32-bit architectures or Double on 64-bit ones (You can detect this at run- or compile-time with CGFloat.NativeType) and cgFloat.native.

From the CoreGraphics source code, in CGFloat.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

*Specifically, longs and pointers, hence the LP. See also: http://www.unix.org/version2/whatsnew/lp64_wp.html

Ky -
  • 30,724
  • 51
  • 192
  • 308
  • 1
    CGFloat also has an instance property called `native` that returns self in the native type (Float or Double as specified above). – Peter Schorn Aug 06 '20 at 19:22
  • Thanks for pointing that out, @PeterSchorn! Not sure why I didn't mention it in the answer – Ky - Aug 07 '20 at 14:18
2

just mention that - Jan, 2020 Xcode 11.3/iOS13

Swift 5

From the CoreGraphics source code

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