2009-11-05 45 views
106

Kể từ khi nâng cấp lên Xcode mới nhất 3.2.1 và Snow Leopard, tôi đã nhận được cảnh báoCảnh báo: "định dạng không phải là một chuỗi chữ và không có đối số định dạng"

"định dạng

không phải là một chuỗi chữ và không có định dạng đối số"

từ đoạn mã sau:

NSError *error = nil; 

if (![self.managedObjectContext save:&error]) 
{ 
    NSLog([NSString stringWithFormat:@"%@ %@, %@", 
     errorMsgFormat, 
     error, 
     [error userInfo]]);  

} 

Nếu errorMsgFormat là một NSString với định dạng specifiers (ví dụ: "print me like this: %@"), có gì sai với cuộc gọi NSLog ở trên? Và cách được khuyến nghị để khắc phục nó để cảnh báo không được tạo ra là gì?

Trả lời

109

Bạn có lồng ghép đúng không? Tôi không nghĩ rằng NSLog() thích chỉ tham gia một đối số, đó là những gì bạn đang truyền. Ngoài ra, nó đã thực hiện định dạng cho bạn. Tại sao không chỉ làm điều này?

NSLog(@"%@ %@, %@", 
    errorMsgFormat, 
    error, 
    [error userInfo]);    

Hoặc, vì bạn nói errorMsgFormat là chuỗi định dạng với một trình giữ chỗ duy nhất, bạn có đang cố thực hiện việc này không?

NSLog(@"%@, %@", [NSString stringWithFormat:errorMsgFormat, error], 
    [error userInfo]);    
+14

"Tôi không nghĩ rằng NSLog() thích chỉ dùng một đối số" 'NSLog()' có thể lấy một đối số, khi chuỗi định dạng không chứa định dạng chỉ định. – user102008

+0

Cung cấp một cảnh báo khác Đối số dữ liệu không được sử dụng bởi chuỗi định dạng. – hasan83

10

cách nhanh nhất để sửa chữa nó sẽ có thêm @"%@", như là đối số đầu tiên NSLog cuộc gọi của bạn, ví dụ:

NSLog(@"%@", [NSString stringWithFormat: ....]); 

Mặc dù, có lẽ bạn nên xem xét câu trả lời Sixteen của Otto.

2

NSLog() dự kiến ​​một chuỗi định dạng, những gì được truyền vào chỉ là một chuỗi. Bạn không cần phải sử dụng stringWithFormat :, bạn chỉ có thể làm:

NSLog(@"%@ %@, %@", errorMsgFormat, error, [error userInfo])

Và đó sẽ làm cho các cảnh báo biến mất.

155

Xcode đang phàn nàn vì đây là sự cố bảo mật.

Đây là mã tương tự như của bạn:

NSString *nameFormat = @"%@ %@"; 
NSString *firstName = @"Jon"; 
NSString *lastName = @"Hess %@"; 
NSString *name = [NSString stringWithFormat:nameFormat, firstName, lastName]; 
NSLog(name); 

Đó tuyên bố NSLog cuối cùng sẽ được thực hiện tương đương với điều này:

NSLog(@"Jon Hess %@"); 

Điều đó sẽ gây NSLog để tìm kiếm một đối số chuỗi hơn nhưng không có. Bởi vì cách ngôn ngữ C hoạt động, nó sẽ lấy một số con trỏ rác ngẫu nhiên từ ngăn xếp và cố gắng xử lý nó như một NSString. Điều này rất có thể sẽ làm hỏng chương trình của bạn. Bây giờ các chuỗi của bạn có thể không có% @ trong chúng, nhưng một số ngày chúng có thể. Bạn nên luôn sử dụng chuỗi định dạng có dữ liệu mà bạn kiểm soát rõ ràng làm đối số đầu tiên cho các hàm có chuỗi định dạng (printf, scanf, NSLog, - [NSString stringWithFormat:], ...).

Như Otto chỉ ra, bạn nên có lẽ chỉ làm điều gì đó như:

NSLog(errorMsgFormat, error, [error userInfo]); 
+17

Và một lần nữa trên SO, các câu trả lời chi tiết và tốt rơi vào lề đường. Cảm ơn bạn đã giải thích đầy đủ điều này. Tôi sẽ không bao giờ tìm ra điều này. –

2

Nếu bạn muốn thoát khỏi cảnh báo "định dạng không phải là một chuỗi chữ và không có đối số định dạng" một lần và cho tất cả, bạn có thể vô hiệu hóa cài đặt cảnh báo GCC "Đánh máy cuộc gọi đến printf/scanf" (GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = NO) trong cài đặt xây dựng của mục tiêu của bạn.

+5

Điều đó sẽ làm im lặng cảnh báo, nhưng nó sẽ không làm bất cứ điều gì để khắc phục lỗi cơ bản trong ứng dụng của bạn.Bằng cách tắt tiếng cảnh báo, bạn sẽ bỏ qua một lỗi tiềm ẩn có thể làm hỏng ứng dụng của bạn dựa trên dữ liệu do người dùng nhập (hoặc trong trường hợp này là thông báo lỗi được tạo bởi CoreData). Nó sẽ là tốt hơn để làm theo một số câu trả lời khác trong câu hỏi này để loại bỏ các lỗi trong mã nguồn gây ra cảnh báo xuất hiện. –

+2

True ... Đó là lý do tại sao tôi đăng "thoát khỏi cảnh báo" thay vì "giải quyết". – aldi

+0

Tôi chạy vào một trường hợp thư viện uthash đang kích hoạt cảnh báo này về các cuộc gọi đến hàm utstring_printf của nó, vì vậy điều này rất hữu ích trong các trường hợp cảnh báo sai. – alfwatt

10

Tôi vừa mới chuyển một số không để phủ nhận các cảnh báo, có thể điều đó sẽ phù hợp với bạn?

NSLog (myString, nil);

+5

Ai đó có thể giải thích TẠI SAO chuyển nil là tham số thứ hai giải quyết cảnh báo? – cprcrack

+1

Truyền nil là rõ ràng trong khi thiếu tham số thứ hai thì không. Bạn có thể giả định lò sưởi của bạn không được thắp sáng khi bạn rời khỏi nhà hoặc bạn có thể chắc chắn rằng nó không phải là. Trong khi không có gì thường xảy ra bởi vì bạn hiếm khi sử dụng lò sưởi của bạn, nó sẽ là một thời gian khi nó là ngôi nhà của bạn bỏng xuống. –

+1

@SoldOutActivist Không hữu ích. Điểm không rõ ràng ở đây (đối với một người không đến từ nền C) là sự khác biệt trong hành vi là giữa việc chuyển một con số rõ ràng và không chuyển bất kỳ thứ gì, và nhận xét của bạn không giải thích điều đó. –

2

FWIW, điều này cũng áp dụng cho nhà phát triển iPhone. Tôi đang mã hóa chống lại các 3.1.3 SDK, và có cùng một lỗi với cùng một vấn đề (lồng stringWithFormat bên trong NSLog()). Sixten và Jon đang kiếm tiền.

37

Câu trả lời cuối cùng: Như Jon Hess đã nói, đó là vấn đề bảo mật vì bạn đang chuyển chuỗi WHATEVER tới một hàm đang chờ chuỗi định dạng. Nghĩa là, nó sẽ đánh giá tất cả các bộ định dạng định dạng WITHIN chuỗi bất kỳ. Nếu không có, tuyệt vời, nhưng nếu có, những điều xấu có thể xảy ra.

Điều thích hợp để làm, sau đó, là sử dụng một chuỗi định dạng trực tiếp, ví dụ

NSLog(@"%@", myNSString); 

Bằng cách đó, ngay cả khi có định dạng specifiers trong myNSString, họ không nhận được đánh giá bởi NSLog.

13

Tôi không đặc biệt khuyên bạn nên sử dụng điều này, vì cảnh báo IS là cảnh báo thực .. sử dụng năng động của ngôn ngữ có thể thực hiện mọi thứ khi chạy chuỗi (tức là chèn thông tin mới hoặc thậm chí là hỏng chương trình). . Tuy nhiên nó có thể để buộc ngăn chặn nếu bạn biết rằng nó phải như thế này và bạn thực sự không muốn được cảnh báo về nó ..

#pragma GCC diagnostic ignored "-Wformat-security"

sẽ nói GCC để tạm thời bỏ qua các cảnh báo biên soạn .. Một lần nữa nó không giải quyết bất cứ điều gì nhưng có thể có lần khi bạn không thể tìm thấy một cách tốt để thực sự khắc phục vấn đề.

EDIT: Theo tiếng kêu, pragma đã thay đổi. Thấy điều này: https://stackoverflow.com/a/17322337/3937

-2
NSLog(@"%@ %@, %@", 
     errorMsgFormat, 
     error, 
     [error userInfo]); 
+1

Sử dụng 'stringWithFormat' là dư thừa ở đây khi bạn có thể thực hiện' NSLog (@ "% @% @,% @", errorMsgFormat, lỗi, [error userInfo]) ' –

0

Chỉ cần để cho ai biết sử dụng appendFormat trên NSMutableString cũng có thể gây ra cảnh báo này xuất hiện nếu cố gắng để vượt qua trong một chuỗi định dạng giống như vậy:

NSMutableString *csv = [NSMutableString stringWithString:@""]; 
NSString *csvAddition = [NSString stringWithFormat:@"%@",WHATEVERYOUAREPUTTINGINYOURSTRING]; 
[csv appendFormat:csvAddition]; 

Vì vậy, để tránh cảnh báo này , hãy chuyển phần trên vào điều này:

NSMutableString *csv = [NSMutableString stringWithString:@""]; 
[csv appendFormat:@"%@",WHATEVERYOUAREPUTTINGINYOURSTRING]; 

Ngắn gọn hơn và an toàn hơn. Thưởng thức!

Các vấn đề liên quan