В чем разница между использованием CGFloat и float?


169

Я склонен использовать CGFloat повсеместно, но мне интересно, получу ли я бессмысленный «удар по производительности» с этим. CGFloat кажется чем-то «тяжелее», чем float, верно? В каких точках я должен использовать CGFloat, и что действительно меняет дело?

Ответы:


193

Как сказал @weichsel, CGFloat - это просто typedef для обоих floatили double. Вы можете убедиться в этом, дважды щелкнув Command на «CGFloat» в Xcode - он перейдет к заголовку CGBase.h, где определен typedef. Тот же подход используется и для NSInteger и NSUInteger.

Эти типы были введены для упрощения написания кода, который работает как на 32-битной, так и на 64-битной версии без изменений. Однако, если все, что вам нужно, это floatточность в вашем собственном коде, вы все равно можете использовать его, floatесли хотите - это несколько уменьшит объем используемой памяти. То же самое касается целочисленных значений.

Я предлагаю вам потратить скромное время, необходимое для того, чтобы сделать приложение 64-разрядным, и попытаться запустить его как таковое, поскольку большинство компьютеров Mac теперь имеют 64-разрядные процессоры, а Snow Leopard полностью 64-разрядный, включая ядро ​​и пользовательские приложения. 64-битное руководство Apple по переходу на какао является полезным ресурсом.


Я думаю, я понял это сейчас. Но на iPhone это, кажется, не имеет большого значения, верно?

4
На айфон, как мы его знаем, нет. Однако всегда разумно использовать код, ориентированный на будущее, и это облегчит безопасное повторное использование одного и того же кода для OS X.
Куинн Тейлор,

Таким образом, вы говорите, в основном, НИКОГДА не используйте float или double напрямую, так как тогда вы будете привязаны к архитектуре процессора (и я думал, что быстрые JVM решат это несколько лет назад :)). Так какие примитивы безопасны? int?
Дэн Розенстарк

9
Я не говорил НИКОГДА не использовать примитив напрямую. Иногда прямые примитивы могут быть проблематичными, например, если переменная может использоваться для хранения данных, которые могут переполниться, например, в 64-битной среде. В целом, использование зависящих от архитектуры typedefs безопаснее, так как этот код с меньшей вероятностью взорвется на другой архитектуре. Однако иногда использование 32-битного типа может быть абсолютно безопасным и сэкономить вашу память. Размер примитивов может быть меньшей проблемой в JVM, но Obj-C и C компилируются, и смешивание 32- и 64-битных библиотек и кода действительно проблематично.
Куинн Тейлор

1
@QuinnTaylor Можете ли вы привести практический пример того, как float переполняется, а CGFloat - нет? И float, и CGFloat имеют конечное число битов. Вы можете переполнить их, храня больше битов, чем они могут содержать.
Pwner

76

CGFloat - это обычное число с плавающей точкой в ​​32-битных системах и двойное число в 64-битных системах.

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

Таким образом, вы не получите никакого штрафа за производительность.


3
Ну, вы используете вдвое больше памяти, если беспокоитесь о памяти.
Тайлер

8
Только на 64-битной.
Куинн Тейлор

13
Правильно, iPhone OS 32-битная. Если подумать, iPhone не использует ограничение 32 ГБ ОЗУ в 4 ГБ и не использует процессор Intel (для которого 64-разрядная скорость быстрее, чем 32-разрядная). Кроме того, он использует Modern Runtime (в отличие от Legacy Runtime 32-разрядных на настольном компьютере - для этих терминов достаточно SO), поэтому он может делать практически все, что может 64-разрядная OS X. Возможно, когда-нибудь мы увидим устройство, которое работает под управлением iPhone OS и является 64-битным, но в настоящее время его нет.
Куинн Тейлор

23
Введите: iPhone 5S
Dgund

7
5S сейчас находится в 64-битном режиме, в последний раз, когда я входил на конференцию (Лондон), они сказали, что способ запуска 32-битных приложений на ios7 - это запуск другого пула общего кэша в памяти, что может привести к увеличению общего объема памяти. так что его def стоит конвертировать все до 64 бит. (если вы не хотите поддерживать 5.1+ или 6.0+ до сих пор)
phil88530

2

Как уже говорили другие, CGFloat является плавающей точкой на 32-битных системах и двойной на 64-битных системах. Однако решение сделать это было унаследовано от OS X, где оно было принято на основе характеристик производительности ранних процессоров PowerPC. Другими словами, вы не должны думать, что float предназначен для 32-битных процессоров, а double - для 64-битных процессоров. (Я полагаю, что процессоры ARM от Apple смогли обработать удвоения задолго до того, как они стали 64-разрядными.) Основной удар по производительности при использовании двойников заключается в том, что они используют вдвое больше памяти и, следовательно, могут работать медленнее, если вы выполняете много операций с плавающей запятой. ,


2

Objective-C

Из исходного кода Foundation, в 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

Авторское право (c) 2000-2011 Apple Inc.

Это по существу делает:

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

Где __LP64__указывает, является ли текущая архитектура * 64-битной.

Обратите внимание, что 32-разрядные системы по-прежнему могут использовать 64-разрядные double, просто требуется больше процессорного времени, поэтому CoreGraphics делает это для целей оптимизации, а не для совместимости. Если вы не беспокоитесь о производительности, но беспокоитесь о точности, просто используйте double.

стриж

В Swift CGFloatэто structоболочка Floatдля 32-битных или Double64 -битных архитектур (вы можете обнаружить это во время выполнения или во время компиляции CGFloat.NativeType)

Из исходного кода CoreGraphics, в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

* Конкретно, longs и указатели, отсюда LP. Смотрите также: http://www.unix.org/version2/whatsnew/lp64_wp.html


1

просто упомянуть, что - январь 2020 года Xcode 11.3 / iOS13

Swift 5

Из исходного кода 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
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.