Specyfikator NSLog / printf dla NSInteger?

132

A NSIntegerma 32 bity na platformach 32-bitowych i 64 bity na platformach 64-bitowych. Czy istnieje NSLogspecyfikator, który zawsze odpowiada rozmiarowi NSInteger?

Ustawiać

  • Xcode 3.2.5
  • Kompilator llvm 1.6 (to ważne; gcc tego nie robi)
  • GCC_WARN_TYPECHECK_CALLS_TO_PRINTF włączone

To przysparza mi trochę żalu:

#import <Foundation/Foundation.h>

int main (int argc, const char * argv[]) {
    @autoreleasepool {
        NSInteger i = 0;
        NSLog(@"%d", i);
    }
    return 0;
}

W przypadku kodu 32-bitowego potrzebuję %dspecyfikatora. Ale jeśli używam %dspecyfikatora, pojawia się ostrzeżenie podczas kompilacji dla wersji 64-bitowej, sugerujące użycie %ldzamiast tego.

Jeśli używam %lddopasowania rozmiaru 64-bitowego, podczas kompilacji dla kodu 32-bitowego pojawia się ostrzeżenie sugerujące użycie %dzamiast tego.

Jak naprawić oba ostrzeżenia jednocześnie? Czy istnieje specyfikator, którego mogę użyć i który działa na którymkolwiek z nich?

Ma to również wpływ [NSString stringWithFormat:]i [[NSString alloc] initWithFormat:].

Steven Fisher
źródło

Odpowiedzi:

297

Zaktualizowana odpowiedź:

Możesz użyć modyfikatorów zi tdo obsługi NSIntegeri NSUIntegerbez ostrzeżeń na wszystkich architekturach.

Chcesz używać %zddla podpisanych, %tuniepodpisanych i %txszesnastkowych.

Te informacje pochodzą dzięki uprzejmości Grega Parkera .


Oryginalna odpowiedź:

Oficjalnym zalecanym podejściem jest użycie %ldjako specyfikacją i oddać rzeczywisty argument do long.

Lily Ballard
źródło
6
To zdecydowanie droga do zrobienia, ale myślę, że mógłbym skorzystać static inline NSIntToLong(NSInteger i) {return (long)i;}. Pozwala to uniknąć całkowitego wyłączenia sprawdzania typu (tj. Jeśli typ i się zmieni).
Steven Fisher
3
Dobre myślenie autorstwa @ steven-fisher. Unikaj ostrzeżeń:static inline long NSIntToLong(NSInteger i) {return (long)i;}
Erik
3
Możesz również utworzyć NSNumber i zarejestrować go. NSLog(@"%@",@(mynsint)); stackoverflow.com/questions/20355439/…
orkoden
2
@KevinBallard To nie powinno być poważnym problemem z wydajnością. I tak nie powinieneś używać dużo NSLog w kodzie produkcyjnym. Jeśli z jakiegoś powodu musisz rejestrować wiele rzeczy, zrób to w osobnym wątku.
orkoden
4
Od Xcode 9.3 pojawia się ostrzeżenie podczas używania NSInteger jako argumentu formatu z %zd:Values of type 'NSInteger' should not be used as format arguments; add an explicit cast to 'long' instead
Rob MacEachern
2

Przyjęta odpowiedź jest absolutnie rozsądna, zgodna ze standardami i poprawna. Jedynym problemem jest to, że już nie działa, co jest całkowitą winą Apple'a.

Format% zd to standardowy format C / C ++ dla size_t i ssize_t. Podobnie jak NSInteger i NSUInteger, size_t i ssize_t są 32-bitowe w systemie 32-bitowym i 64-bitowym w systemie 64-bitowym. I dlatego drukowanie NSInteger i NSUInteger przy użyciu% zd działało.

Jednak NSInteger i NSUInteger są zdefiniowane jako „długie” w systemie 64-bitowym i jako „int” w systemie 32-bitowym (czyli 64-bitowym). Obecnie size_t jest zdefiniowany jako „long” we wszystkich systemach, który ma taki sam rozmiar jak NSInteger (64- lub 32-bitowy), ale jest innego typu. Albo ostrzeżenia Apple uległy zmianie (więc nie pozwala na przekazanie niewłaściwego typu do printf, mimo że ma odpowiednią liczbę bitów), albo podstawowe typy dla size_t i ssize_t uległy zmianie. Nie wiem który, ale% zd jakiś czas temu przestał działać. Obecnie nie ma formatu, który drukowałby NSInteger bez ostrzeżenia w systemach 32- i 64-bitowych.

Więc jedyne, co możesz niestety zrobić: Użyj% ld i rzutuj swoje wartości z NSInteger na long lub z NSUInteger na unsigned long.

Gdy nie będziesz już tworzyć wersji 32-bitowej, możesz po prostu użyć% ld bez rzutowania.

gnasher729
źródło
0

Elementy formatujące pochodzą ze standardowej funkcji printf systemu UNIX / POSIX. Użyj % lu dla unsigned long ,% ld dla long,% lld dla long i % llu dla unsigned long . Wypróbuj man printf na konsoli, ale na Macu jest niekompletny. Strony podręcznika systemu Linux są bardziej przejrzyste http://www.manpages.info/linux/sprintf.3.html

Oba ostrzeżenia można naprawić tylko przez NSLog (@ "% lu", (unsigned long) arg); połączone z rzutowaniem, ponieważ kod zostanie skompilowany w wersji 32 i 64-bitowej na iOS. W przeciwnym razie każda kompilacja tworzy osobne ostrzeżenie.

kot
źródło