NSInteger에 대한 NSLog / printf 지정자?


131

A NSInteger는 32 비트 플랫폼에서 32 비트이고 64 비트 플랫폼에서 64 비트입니다. NSLog의 크기와 항상 일치 하는 지정자가 NSInteger있습니까?

설정

  • Xcode 3.2.5
  • llvm 1.6 컴파일러 (이것은 중요합니다; gcc는 이것을하지 않습니다)
  • GCC_WARN_TYPECHECK_CALLS_TO_PRINTF

그로 인해 여기에 슬픔이 생겼습니다.

#import <Foundation/Foundation.h>

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

32 비트 코드의 %d경우 지정자가 필요 합니다. 그러나 %d지정자를 사용하면 64 비트를 컴파일 할 때 %ld대신 사용하라는 경고 메시지가 표시됩니다 .

%ld64 비트 크기를 일치시키는 데 사용 하면 32 비트 코드를 컴파일 할 때 %d대신 사용하라는 경고 메시지가 표시 됩니다.

두 경고를 한 번에 해결하려면 어떻게합니까? 어느 쪽에서 나 사용할 수있는 지정자가 있습니까?

이 또한 영향 [NSString stringWithFormat:][[NSString alloc] initWithFormat:].

답변:


296

업데이트 된 답변 :

모든 아키텍처 에서 zt수정자를 사용하여 경고 를 처리 NSInteger하거나 NSUInteger경고없이 처리 할 수 있습니다 .

당신은 사용하고자하는 %zd서명에 대한 %tu서명을 위해, 그리고 %tx진수를 위해.

이 정보는 Greg Parker 가 제공 합니다.


원래 답변 :

공식 권장되는 방법은 사용하는 것입니다 %ld귀하의 지정자로하고,에 실제 인수를 캐스팅 long.


6
이것은 확실히 갈 길이지만, 나는 사용할 것이라고 생각합니다 static inline NSIntToLong(NSInteger i) {return (long)i;}. 이렇게하면 유형 검사가 완전히 비활성화되지 않습니다 (예 : i 유형이 변경되는 경우).
Steven Fisher

3
@ steven-fisher의 좋은 생각. 에 경고를 피하십시오 :static inline long NSIntToLong(NSInteger i) {return (long)i;}
Erik

3
NSNumber를 생성하고 기록 할 수도 있습니다. NSLog(@"%@",@(mynsint)); stackoverflow.com/questions/20355439/…
orkoden 2012 년

2
@KevinBallard 심각한 성능 문제는 아닙니다. 어쨌든 프로덕션 코드에 많은 NSLog를 사용해서는 안됩니다. 어떤 이유로 많은 물건을 기록 해야하는 경우 별도의 스레드에서 수행하십시오.
orkoden

4
Xcode 9.3부터 NSInteger를 다음과 같은 형식 인수로 사용할 때 경고가 발생합니다 %zd.Values of type 'NSInteger' should not be used as format arguments; add an explicit cast to 'long' instead
Rob MacEachern

2

허용되는 답변은 절대적으로 합리적이며 표준을 준수하며 정확합니다. 유일한 문제는 더 이상 작동하지 않는다는 것인데, 이는 완전히 애플의 잘못입니다.

% zd 형식은 size_t 및 ssize_t의 C / C ++ 표준 형식입니다. NSInteger 및 NSUInteger와 같이 size_t 및 ssize_t는 32 비트 시스템에서 32 비트이고 64 비트 시스템에서 64 비트입니다. 이것이 % zd를 사용하여 NSInteger와 NSUInteger를 인쇄하는 이유입니다.

그러나 NSInteger 및 NSUInteger는 64 비트 시스템에서 "long"으로 정의되고 32 비트 시스템 (64 대 32 비트)에서 "int"로 정의됩니다. 오늘날,이 size_t는 모든 시스템의 "긴"에 정의되어 있다 NSInteger (중 64 또는 32 비트)와 동일한 크기이지만 상이한 유형. Apple의 경고가 변경되었으므로 (올바른 비트 수가 있더라도 잘못된 유형을 printf에 전달할 수 없음) size_t 및 ssize_t의 기본 유형이 변경되었습니다. 어느 것을 모르지만 % zd가 얼마 전에 작동을 멈췄습니다. 현재 32 비트 및 64 비트 시스템 모두에서 NSInteger를 경고없이 인쇄하는 형식 은 없습니다 .

따라서 불행히도 할 수있는 유일한 일 : % ld를 사용하고 값을 NSInteger에서 long으로 또는 NSUInteger에서 unsigned long으로 캐스트하십시오.

더 이상 32 비트를 빌드하지 않으면 캐스트없이 % ld 만 사용할 수 있습니다.


0

포맷터는 표준 UNIX / POSIX printf 기능에서 제공됩니다. 사용 % 루서명 오래 , 오래 %의 LD, 오래 오래 %의 LLD, 그리고 %의 LLU 에 대한 부호 오래 오래 . 콘솔에서 man printf를 시도하지만 Mac에서는 불완전합니다. 리눅스 맨 페이지는보다 명백하다 http://www.manpages.info/linux/sprintf.3.html

두 경고는 모두 NSLog (@ "% lu", (unsigned long) arg)로만 해결할 수 있습니다. 코드가 iOS 용 32 및 64 비트로 컴파일되므로 캐스트와 결합됩니다. 그렇지 않으면 각 컴파일마다 별도의 경고가 생성됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.