Trình xác định NSLog / printf cho NSInteger?


131

A NSIntegerlà 32 bit trên nền tảng 32 bit và 64 bit trên nền tảng 64 bit. Có một NSLogspecifier luôn luôn phù hợp với kích thước của NSInteger?

Thiết lập

  • Xcode 3.2.5
  • trình biên dịch llvm 1.6 (điều này rất quan trọng; gcc không làm điều này)
  • GCC_WARN_TYPECHECK_CALLS_TO_PRINTF đã bật lên

Điều đó gây cho tôi một số đau buồn ở đây:

#import <Foundation/Foundation.h>

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

Đối với mã 32 bit, tôi cần %dspecifier. Nhưng nếu tôi sử dụng trình %dxác định, tôi sẽ nhận được cảnh báo khi biên dịch 64 bit cho thấy tôi sử dụng %ldthay thế.

Nếu tôi sử dụng %ldđể khớp với kích thước 64 bit, khi biên dịch mã 32 bit, tôi nhận được cảnh báo đề nghị tôi sử dụng %dthay thế.

Làm cách nào để sửa cả hai cảnh báo cùng một lúc? Có một specifier tôi có thể sử dụng mà làm việc trên một trong hai?

Điều này cũng tác động [NSString stringWithFormat:][[NSString alloc] initWithFormat:].

Câu trả lời:


296

Cập nhật câu trả lời:

Bạn có thể sử dụng ztsửa đổi để xử lý NSIntegerNSUIntegerkhông có cảnh báo, trên tất cả các kiến ​​trúc.

Bạn muốn sử dụng %zdđể ký, %tukhông dấu và %txhex.

Thông tin này được cung cấp bởi Greg Parker .


Câu trả lời gốc:

Cách tiếp cận được đề xuất chính thức là sử dụng %ldlàm công cụ xác định của bạn và đưa đối số thực tế sang a long.


6
Đây chắc chắn là con đường để đi, nhưng tôi nghĩ rằng tôi có thể sử dụng static inline NSIntToLong(NSInteger i) {return (long)i;}. Điều này tránh việc vô hiệu hóa kiểm tra loại hoàn toàn (nghĩa là nếu loại i thay đổi).
Steven Fisher

3
Suy nghĩ tốt bởi @ steven-fishing. Tránh cảnh báo với:static inline long NSIntToLong(NSInteger i) {return (long)i;}
Erik

3
Bạn cũng có thể tạo NSNumber và đăng nhập đó. NSLog(@"%@",@(mynsint)); stackoverflow.com/questions/20355439/ từ
orkoden

2
@KevinBallard Đây không phải là một vấn đề hiệu suất nghiêm trọng. Bạn không nên sử dụng nhiều NSLog trong mã sản xuất. Nếu bạn phải đăng nhập nhiều thứ vì một số lý do, hãy thực hiện nó trên một luồng riêng biệt.
orkoden

4
Kể từ Xcode 9.3, có một cảnh báo khi sử dụng NSInteger làm đối số định dạng với %zd:Values of type 'NSInteger' should not be used as format arguments; add an explicit cast to 'long' instead
Rob MacEacéc

2

Câu trả lời được chấp nhận là hoàn toàn hợp lý, đó là tuân thủ tiêu chuẩn và chính xác. Vấn đề duy nhất là nó không hoạt động nữa, đó hoàn toàn là lỗi của Apple.

Định dạng% zd là định dạng chuẩn C / C ++ cho size_t và ssize_t. Giống như NSInteger và NSUInteger, size_t và ssize_t là 32 bit trên hệ thống 32 bit và 64 bit trên hệ thống 64 bit. Và đó là lý do tại sao in NSInteger và NSUInteger bằng% zd hoạt động.

Tuy nhiên, NSInteger và NSUInteger được định nghĩa là "dài" trên hệ thống 64 bit và là "int" trên hệ thống 32 bit (là 64 so với 32 bit). Hôm nay, size_t được định nghĩa về "dài" trên tất cả các hệ thống, đó kích thước giống như NSInteger (hoặc 64 hoặc 32 bit), nhưng một loại khác nhau. Các cảnh báo của Apple đã thay đổi (vì vậy nó không cho phép chuyển loại sai sang printf, mặc dù nó có đúng số bit) hoặc các loại cơ bản cho size_t và ssize_t đã thay đổi. Tôi không biết cái nào, nhưng% zd đã ngừng hoạt động một thời gian trước đây. Có không định dạng ngày hôm nay rằng sẽ in NSInteger mà không cần cảnh báo trên cả hai hệ thống 32 và 64 bit.

Vì vậy, điều duy nhất bạn có thể làm không may: Sử dụng% ld và chuyển các giá trị của bạn từ NSInteger thành dài hoặc từ NSUInteger sang dài không dấu.

Khi bạn không xây dựng thêm 32 bit nữa, bạn chỉ có thể sử dụng% ld mà không cần bất kỳ diễn viên nào.


0

Các trình định dạng đến từ chức năng printf UNIX / POSIX tiêu chuẩn. Sử dụng % lu cho dài không dấu ,% ld cho dài,% lld cho dài dài và % llu cho dài không dấu . Hãy thử man printf trên bảng điều khiển, nhưng trên Mac thì không đầy đủ. Các trang web linux rõ ràng hơn http://www.manpages.info/linux/sprintf.3.html

Cả hai cảnh báo chỉ có thể được sửa bởi NSLog (@ "% lu", (không dấu dài) arg); kết hợp với một diễn viên là mã sẽ được biên dịch trong 32 VÀ 64 bit cho iOS. Nếu không, mỗi phần tổng hợp tạo ra một cảnh báo riêng.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.