NSString stringWithFormat: с любопытным поведением %zd на 32-битных устройствах

Почему мы не можем отформатировать строку, используя «%zd», как ожидается, на 32-битных устройствах (iPhone5, iPhone4 или их симуляторах)?

int64_t test1 = 11111111;
int64_t test2 = 22222222;
int64_t test3 = 33333333;
int64_t test4 = 44444444;
NSString *testStr = [NSString stringWithFormat:@"\"%zd %zd %zd %zd\"", test1, test2, test3, test4];
NSLog(@"testStr: %@", testStr);

NSInteger test5 = 55555555;
NSInteger test6 = 66666666;
NSInteger test7 = 77777777;
NSInteger test8 = 88888888;
testStr = [NSString stringWithFormat:@"\"%zd %zd %zd %zd\"", test5, test6, test7, test8];
NSLog(@"testStr: %@", testStr);

Журнал:

2017-09-12 05:53:59.462: testStr:"11111111 0 22222222 0"
2017-09-12 05:53:59.465: testStr:"55555555 66666666 77777777 88888888"

person Ziiip    schedule 12.09.2017    source источник


Ответы (1)


Примечание. Ответ только что набран на планшете, образец не тестировался, так что это предположение.

Формат %zd предназначен для значений типа size_t, а не для 64-битных значений.

Попробуйте использовать %lld для значений int64_t, long long — это 64 бита как в 32-битной, так и в 64-битной версиях iOS.

Для NSInteger попробуйте %ld и приведите аргументы к long, потому что размер NSInteger зависит от платформы.

ХТН

person CRD    schedule 12.09.2017
comment
Думаю, вы для вашего ответа. Извините за медленный ответ. Я знаю, что ты говоришь, и ты отвечаешь чертовски правильно. Но я до сих пор не знаю, почему поведение такое загадочное (посмотрите на первый вывод). - person Ziiip; 16.10.2017
comment
Когда аргументы передаются функции/методу с переменным аргументом, например stringWithFormat:, байты каждого значения аргумента размещаются в стеке непрерывно. Переменная test1 является 64-битной, поэтому 8 байтов помещаются в стек, за ними следуют 8 байтов test2 и т. д. В 32-битных %zd форматирует 32-битное значение, поэтому для каждого вхождения %zd в Строка формата Используются 4 байта из стека. Когда десятичное значение 11111111 записывается как 64-битное двоичное число, все верхние 32 бита равны 0. Таким образом, 8 байтов test1 форматируются как два 4-байтовых значения, второе из которых 0. - person CRD; 16.10.2017
comment
Звучит разумно! Большое спасибо. И где я могу этому научиться? это интересное знание, о котором я не знаю. - person Ziiip; 20.10.2017
comment
Искать знания всегда хорошо! Два источника, которые вы можете исследовать: вы можете исследовать ABI используемого вами компилятора/процессора/ОС; а про генерацию кода можно прочитать в книге по компиляторам. Например, классическая книга Компиляторы Ахо и Ульмана, также известная как Dragon Book, описывает последовательность вызовов с упоминанием функций с переменными аргументами, таких как printf() в C, хотя она была опубликована более десять лет назад он устарел по стандартам информатики! ;-) - person CRD; 20.10.2017
comment
Спасибо, что указали мне правильное направление. Для меня большая честь получить от вас отличные ответы. - person Ziiip; 20.10.2017