Учебник по типу CFNumber
Введение
Объект CFNumber
инкапсулирует C
числовых типов. Он используется в различных случаях в Core Foundation API. Следовательно, очень полезно знать, как работает этот тип. Мы разработали программу командной строки, которая демонстрирует некоторые случаи использования CFNumber.
Исходный код
Исходный код программы можно найти здесь.
Запуск программы
Если вы скомпилируете и запустите программу, вы получите следующий вывод:
❯ ./CFNumberDemo Address of temperature 0x7ffee9824d50 Value of pTemperature 0x7face3504dd0 Value of myFuncAddress 0x1063dd5a0 --------------------------- Get Types:... ui number type is kCFNumberLongType = NO ui number type is kCFNumberSInt64Type = YES f number type is kCFNumberFloatType = NO f number type is kCFNumberFloat32Type = YES temperatureAddress number type is kCFNumberLongLongType = NO temperatureAddress number type is kCFNumberSInt64Type = YES pTemperature number type is kCFNumberLongLongType = NO pTemperature number type is kCFNumberSInt64Type = YES myFuncAddress number type is kCFNumberLongLongType = NO myFuncAddress number type is kCFNumberSInt64Type = YES --------------------------- Get Values:... ui value retrieved = 5 f value retrieved = 8.20 temperatureAddress value retrieved = 0x7ffee9824d50 Temperature maximum 40, minimum 32 pTemperature value retrieved = 0x7face3504dd0 Temperature maximum 42, minimum 31 myFuncAddress value retrieved = 0x1063dd5a0 Call function via returned value to prove that it works... res = 3 ---------------------------
Беззнаковое целое
Программа демонстрирует случай unsigned int
и то, как вы можете обернуть его как CFNumber
.
- строка 1: переменной
ui
присваивается значение5
. - строки 3–5: мы создаем
CFNumber
, обертывающее значение переменнойui
. Обратите внимание, что мы вызываем функциюCFNumberCreate()
и указываем распределитель по умолчанию (kCFAllocatorDefault
) и типkCFNumberLongType
в качестве типа числа, которое мы хотим обернуть. Наконец, и это очень важно, мы предоставляем адрес памяти, в которой хранится значение, которое мы хотим обернуть, какCFNumber
. - строки 10–14: эти строки демонстрируют, что Core Foundation может наконец обернуть число типом, отличным от того, который мы указываем при вызове функции
CFNumberCreate()
.CFNumberGetType()
возвращаетkCFNumberSInt64Type
для значения5
, которое мы сохранили, даже если мы создали его с типомkCFNumberLongType
. - строки 22–24: эти строки демонстрируют, как мы можем получить значение за объектом
CFNumber
. Мы используем функциюCFNumberGetValue()
. Мы определили тип, который мы использовали при созданииCFNumber
, и адрес памяти, где мы хотим сохранить возвращаемое значение. Программа печатает значение5
в качестве возвращаемого значения. Обратите внимание, что хотя мы изменили значение, хранящееся в исходной переменной (ui = 8
), это изменение не отражается на значении, которое мы получаем изCFNumberGetValue()
, потому чтоCFNumber
создает копию значения, которое мы передаем в функциюCFNumberCreate()
. - строка 27: Мы не должны забывать освобождать ресурсы, зарезервированные объектом
CFNumber
. Это делается с помощью функцииCFRelease()
.
Плавать
Мы переносим число float
в число CFNumber
. Вот часть кода, связанная с этим:
Это не сильно отличается от случая unsigned int
.
- Убедитесь, что функция
CFNumberCreate()
принимает в качестве последнего аргумента адрес памяти, содержащей значение, которое мы хотим обернуть. - Обратите внимание, что в действительности используется тип
kCFNumberFloat32Type
, а неkCFNumberFloatType
, хотя мы указали последний при вызовеCFNumberCreate()
. - Исходное значение копируется, когда мы обертываем/создаем файл
CFNumber
. Следовательно, любое изменение (f = 15.3
) не влияет на значениеCFNumber
, которое возвращает8.20
, когда мы получаем значение сCFNumberGetValue()
. - Не забываем освобождать ресурсы за
CFNumber
вызовомCFRelease()
.
Адрес локальной переменной
Как сохранить адрес локальной переменной в объект CFNumber
? Вот как мы это делаем в нашей демонстрационной программе:
Приведенная выше программа сохраняет адрес переменной temperature
в файле CFNumber
.
- строки 2–7: Сначала мы объявляем другую переменную типа
unsigned long
и сохраняем в ней адрес переменнойtemperature
. Мы делаем это, потому что функцияCFNumberCreate()
требует, чтобы мы передали значение, которое мы хотим поместить вCFNumber
, передав адрес переменной, которая содержит фактическое значение. Поэтому для этой цели используется переменнаяtemperatureAddress
. Обратите также внимание, что мы указываем типCFNumber
какkCFNumberLongLongType
. - строки 13–17: они доказывают, что на самом деле используется тип
kCFNumberSInt64Type
, а неkCFNumberLongLongType
. - строки 24–29: они демонстрируют, как можно вернуть значение, стоящее за
temperatureAddressNumberRef
, и преобразовать его в адрес, указывающий на структуруTemperature
. Пользовательская функцияPrintTemperature()
используется для печати содержимого, результат которой доказывает, что все работает как положено. - строка 34: Не забываем освобождать ресурсы за
CFNumber
с помощью функцииCFRelease()
.
Значение указателя в куче памяти
Мы знаем, что переменная типа указателя содержит значение, указывающее на адрес в памяти. Следовательно, перенос его значения в CFNumber
мало чем отличается от предыдущего случая.
- строка 6: мы хотим обернуть значение, хранящееся внутри
pTemperature
. Следовательно, достаточно передать адрес этой переменной ((const void *)&pTemperature
) в качестве последнего аргумента вCFNumberCreate()
. Следовательно,pTemperatureNumberRef
будет содержать адрес памяти, на который также указываетpTemperature
. - Остальная часть программы доказывает, что все работает так, как ожидалось. Мы получаем значение позади
pTemperatureNumberRef
, используяCFNumberGetValue()
, а затем обрабатываем его как адрес структурыTemperature
, хранящейся в куче. - Мы не должны забывать освобождать как ресурсы за
pTemperatureNumberRef
, с вызовомCFRelease()
, так и память, выделенную в куче для хранения структурыTemperature
.
Адрес глобальной функции
Последний пример, над которым мы работаем в этом посте, — это упаковка адреса функции в виде CFNumber
. Это не сильно отличается от двух предыдущих случаев, потому что этот случай, как и предыдущие, включает преобразование адреса памяти в CFNumber
.
- строки 4–6: мы объявляем и определяем функцию с именем
myFunc
и прототипомint ()(int)
. Он принимает в качестве входных данных целое число и возвращает целочисленное значение, увеличенное на 1. - строки 9–15: так мы получаем адрес функции и заключаем его в
CFNumber
типаkCFNumberLongLongType
. Как видите, мы не можем просто передатьmyFunc
в качестве последнего аргумента функцииCFNumberCreate()
. Это связано с тем, чтоCFNumberCreate()
ожидает, что последним аргументом будет адрес переменной, которая содержит значение, которое мы хотим обернуть. Следовательно, мы сначала определяем переменнуюmyFuncAddress
, чтобы иметь в качестве значения адрес функцииmyFunc
, а затем мы передаем адрес этой переменной в качестве последнего аргумента функцииCFNumberCreate()
((const void *)&myFuncAddress
). - строки 21–25: Как и в предыдущих двух случаях, фактический тип за созданным
CFNumber
— этоkCFNumberSInt64Type
, а неkCFNumberLongLongType
. - строки 32–36: Возвращаем значение с помощью функции
CFNumberGetValue()
. Мы сохраняем значение в новую локальную переменную с именемmyFuncAddressValue
. Командыprintf
используются для печати значения и подтверждения того, что мы получаем ожидаемые результаты. - строка 41: Эта строка доказывает, что значение, хранящееся внутри
myFuncAddressValue
, действительно является адресом функции, которая принимает в качестве входных данных целое число и возвращает обратно целое число, увеличенное на 1. Посмотрите, как мы приводимmyFuncAddressValue
кint (*)(int)
и вызываем функцию с использованием(2)
. Результат, напечатанный в следующей строке, —3
.
Заключительное примечание
В этом посте показаны различные случаи переноса чисел C
в числа Core Foundation, также известные как CFNumber
. Это оказывается весьма полезным, когда вам нужно использовать Core Foundation API, который использует числа в качестве входных или выходных аргументов.
Ваши отзывы всегда более чем приветствуются. Я всегда учусь у вас, даже больше, чем вы могли бы учиться у меня.