Chuyển đổi ngầm định Objective-C mất độ chính xác nguyên 'NSUInteger' (còn gọi là 'dài không dấu') thành cảnh báo 'int'


187

Tôi đang làm việc thông qua một số bài tập và đã có một cảnh báo rằng:

Chuyển đổi ngầm định làm mất độ chính xác của số nguyên: 'NSUInteger' (còn gọi là 'dài không dấu') thành 'int'

#import <Foundation/Foundation.h>

int main (int argc, const char * argv[])
{
    @autoreleasepool {

        NSArray *myColors;

        int i;
        int count;

        myColors = @[@"Red", @"Green", @"Blue", @"Yellow"];

        count = myColors.count; //  <<< issue warning here

        for (i = 0; i < count; i++)

        NSLog (@"Element %i = %@", i, [myColors objectAtIndex: i]);
    }

    return 0;
}

Ảnh chụp màn hình

Câu trả lời:


470

Các countphương pháp NSArraylợi nhuận một NSUInteger, và trên 64-bit nền tảng OS X

  • NSUIntegerđược định nghĩa là unsigned long, và
  • unsigned long là số nguyên không dấu 64 bit.
  • int là số nguyên 32 bit.

Vì vậy, intmột kiểu dữ liệu "nhỏ hơn" NSUInteger, do đó, cảnh báo trình biên dịch.

Xem thêm NSUInteger trong "Tham chiếu kiểu dữ liệu nền tảng":

Khi xây dựng các ứng dụng 32 bit, NSUInteger là số nguyên không dấu 32 bit. Một ứng dụng 64 bit coi NSUInteger là số nguyên không dấu 64 bit.

Để sửa cảnh báo trình biên dịch đó, bạn có thể khai báo countbiến cục bộ là

NSUInteger count;

hoặc (nếu bạn chắc chắn rằng mảng của bạn sẽ không bao giờ chứa nhiều hơn 2^31-1các phần tử!), hãy thêm một biểu mẫu rõ ràng:

int count = (int)[myColors count];

19
Chỉ cần thêm - Tôi đã bỏ phiếu cho câu trả lời này khi tôi nhận được vô số cảnh báo và lỗi bất ngờ trong dự án Xcode 5 của tôi. Bạn đã đề cập đến 64 bit dẫn tôi xem các cài đặt bản dựng của tôi. Xcode đã thay đổi nó thành chế độ 64 bit, điều này đã gây ra lỗi. Thay đổi nó trở lại arvm7 đã sửa tất cả chúng.
Robert J. Clegg

1
@Tander có sự khác biệt về hiệu năng giữa việc biên dịch 64 bit so với armv7 không?
Shaun Budhram

1
@ShaunBudhram Bởi vẻ ngoài của nó không. Tôi chưa thấy sự khác biệt nào. Nó sẽ chỉ tạo ra sự khác biệt trong các ứng dụng sử dụng CPU rất nhiều - ví dụ như các trò chơi sẽ thấy lợi ích biên dịch trong 64 bit.
Robert J. Clegg

7
"Bắt đầu từ ngày 1 tháng 2 năm 2015, các ứng dụng iOS mới được tải lên App Store phải bao gồm hỗ trợ 64 bit ..." - Tin tức và cập nhật dành cho nhà phát triển của Apple, ngày 20 tháng 10 năm 2014
Pang

2
@JayprakashDubey: Apple không thấy cảnh báo trình biên dịch của bạn vì bạn gửi ứng dụng được biên dịch nhị phân cho App Store. Do đó, ứng dụng của bạn không thể bị từ chối vì các cảnh báo của trình biên dịch. Tất nhiên bạn nên sửa chúng để làm cho ứng dụng của bạn hoạt động chính xác.
Martin R

24

Trái với câu trả lời của Martin, truyền vào int (hoặc bỏ qua cảnh báo) không phải lúc nào cũng an toàn ngay cả khi bạn biết mảng của mình không có nhiều hơn 2 ^ 31-1 phần tử. Không phải khi biên dịch cho 64-bit.

Ví dụ:

NSArray *array = @[@"a", @"b", @"c"];

int i = (int) [array indexOfObject:@"d"];
// indexOfObject returned NSNotFound, which is NSIntegerMax, which is LONG_MAX in 64 bit.
// We cast this to int and got -1.
// But -1 != NSNotFound. Trouble ahead!

if (i == NSNotFound) {
    // thought we'd get here, but we don't
    NSLog(@"it's not here");
}
else {
    // this is what actually happens
    NSLog(@"it's here: %d", i);

    // **** crash horribly ****
    NSLog(@"the object is %@", array[i]);
}

6
Bạn đúng rằng việc đúc kết quả indexOfObject:sẽ là một ý tưởng tồi. Câu trả lời của tôi có nghĩa là cho mã cụ thể trong câu hỏi và countphương thức không thể trả về NSNotFound. Tôi không khuyên bạn nên chọn để int hoặc bỏ qua cảnh báo nói chung. Xin lỗi nếu điều đó không rõ ràng. Trong thực tế, mã mẫu của bạn sẽ tạo ra một cảnh báo if (i == NSNotFound)nếu được biên dịch cho 64 bit, vì vậy vấn đề sẽ không được chú ý.
Martin R

@Adrian: Nếu bạn không phiền, bạn đề nghị người hỏi làm gì?
moonman239

@ moonman239 Nói chung, tôi sẽ sử dụng một biến có loại chính xác nếu có thể (đề xuất đầu tiên của @ MartinR) thay vì truyền (lần thứ hai của anh ta). Như ông chỉ ra, việc casting là an toàn trong trường hợp cụ thể này, nhưng tôi nghĩ đó là một thói quen kém để tham gia, vì nó có thể gây ra hậu quả không mong muốn (như trong ví dụ của tôi). Tôi đã đăng bởi vì tôi đã bị cắn bởi tình huống cụ thể này (mặc dù đó là một điểm tốt về cảnh báo trình biên dịch ==, mà tôi phải bỏ qua).
Adrian

2
Tôi nghĩ rằng số lượng sẽ được sử dụng thường xuyên hơn nhiều so với indexOfObject và việc tạo vòng lặp for với NSInteger chỉ để không có kiểu mã hóa "kém" là vô nghĩa. Bạn chỉ nên xem indexOfObject và đảm bảo rằng bạn sử dụng NSIntegers ở đó, mọi thứ chỉ đơn giản là tính một thứ gì đó đều tốt như int, đặc biệt là trong một phương pháp tập trung
NikkyD

5

Thay đổi khóa trong Project> Build Settings " các cuộc gọi typecheck thành printf / scanf : NO "

Giải thích: [Cách thức hoạt động]

Kiểm tra các cuộc gọi đến printf và scanf, v.v., để đảm bảo rằng các đối số được cung cấp có các loại phù hợp với chuỗi định dạng được chỉ định và các chuyển đổi được chỉ định trong chuỗi định dạng có ý nghĩa.

Hy vọng nó hoạt động

Cảnh báo khác

Mục tiêu c chuyển đổi ngầm làm mất độ chính xác nguyên 'NSUInteger' (còn gọi là 'dài không dấu') thành 'int

Thay đổi khóa " chuyển đổi ngầm định thành Loại 32 bit> Gỡ lỗi> * 64 kiến ​​trúc: Không "

[ thận trọng: Nó có thể làm mất hiệu lực cảnh báo khác về chuyển đổi kiến ​​trúc 64 Bits] .


nếu bạn muốn chuyển đổi thư viện 32 bit của mình thành 64 bit, đây là một tùy chọn đầy hứa hẹn.
San

2

Thực hiện đúc ngoại lệ cho "int" giải quyết vấn đề trong trường hợp của tôi. Tôi gặp vấn đề tương tự. Vì thế:

int count = (int)[myColors count];

hay nó được gọi là "ngầm"? LOL :) Trong cả hai trường hợp, nó đã làm việc.
Vladimir Despotovic
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.