Uyarı: "bir dizge değil biçimlendir ve biçim bağımsız değişkeni yok"


110

En son Xcode 3.2.1 ve Snow Leopard'a yükseltme yaptığımdan beri uyarı alıyorum

"biçim bir dizge değil ve biçim bağımsız değişkeni yok"

aşağıdaki koddan:

NSError *error = nil;

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

}

Eğer errorMsgFormatbir olan NSStringbiçim belirteçleri ile (örn: "print me like this: %@") Yukarıdaki sorunun ne NSLogçağrı? Ve uyarının oluşturulmaması için bunu düzeltmenin önerilen yolu nedir?

Yanıtlar:


113

Parantezlerinizi doğru şekilde yerleştiriyor musunuz? NSLog()Tek bir tartışmayı sevdiğini sanmıyorum , o da bunu geçiriyorsun. Ayrıca biçimlendirmeyi sizin için zaten yapıyor. Neden bunu yapmıyorsun?

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

Veya, errorMsgFormattek bir yer tutuculu bir biçim dizesi olduğunu söylediğinize göre , bunu yapmaya mı çalışıyorsunuz?

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

14
"NSLog () 'un yalnızca bir bağımsız değişken almayı sevdiğini sanmıyorum" NSLog(), biçim dizesi hiçbir biçim belirticisi içermediğinde bir bağımsız değişken alabilir.
user102008

Biçim dizesi tarafından kullanılmayan başka bir uyarı Data argümanı verir.
hasan

157

Xcode şikayet ediyor çünkü bu bir güvenlik sorunu.

İşte sizinkine benzer kod:

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

Bu son NSLog ifadesi şunun eşdeğerini çalıştıracak:

NSLog(@"Jon Hess %@");

Bu, NSLog'un bir tane daha string argümanı aramasına neden olacak, ancak bir tane yok. C dilinin çalışma şekli nedeniyle, yığından rastgele bir çöp işaretçisi alacak ve ona bir NSString gibi davranmaya çalışacak. Bu, büyük olasılıkla programınızı çökertecektir. Şimdi dizelerinizde muhtemelen% @ yok, ancak bir gün olabilir. Biçim dizelerini alan işlevlerin (printf, scanf, NSLog, - [NSString stringWithFormat:], ...) ilk bağımsız değişkeni olarak açıkça kontrol ettiğiniz verilerle her zaman bir biçim dizesi kullanmalısınız.

Otto'nun işaret ettiği gibi, muhtemelen şöyle bir şey yapmalısınız:

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

17
Ve bir kez daha SO'da, ayrıntılı ve iyi cevaplar yol kenarına düşüyor. Bunu tam olarak açıkladığınız için TEŞEKKÜR EDERİZ. Bunu asla çözemezdim.
Dan Rosenstark

38

Son cevap: Jon Hess'in dediği gibi, bu bir güvenlik sorunu çünkü bir biçim dizesi bekleyen bir işleve bir WHATEVER dizesi geçiriyorsunuz. Diğer bir deyişle, tüm biçim belirleyicilerini, herhangi bir dizeyle İÇEREN değerlendirecektir. Hiç yoksa harika, ama varsa kötü şeyler olabilir.

O halde yapılacak doğru şey, doğrudan bir biçim dizesi KULLANMAKtır, örneğin

NSLog(@"%@", myNSString);

Bu şekilde, myNSString'de format belirleyicileri olsa bile NSLog tarafından değerlendirilmezler.


13

Uyarı gerçek bir uyarı olduğu için bunu kullanmanızı özellikle tavsiye etmiyorum .. dilin dinamik kullanımında diziye çalışma zamanı yapmak mümkündür (yani yeni bilgi eklemek veya programı çökertmek) .. Ancak bu mümkündür bunun böyle olması gerektiğini BİLİYOR ve gerçekten bu konuda uyarılmak istemiyorsanız, bastırmaya zorlamak için ..

#pragma GCC diagnostic ignored "-Wformat-security"

GCC'ye derleme uyarısını geçici olarak görmezden gelmesini söylerdi .. Yine hiçbir şeyi çözmez, ancak sorunu gerçekten düzeltmenin iyi bir yolunu bulamadığınız zamanlar olabilir.

DÜZENLEME: Clang'dan itibaren pragma değişti. Şuna bakın: https://stackoverflow.com/a/17322337/3937


10

Bunu düzeltmenin en hızlı yolu @"%@",, NSLogaramanıza ilk argüman olarak eklemek olacaktır.

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

Yine de, muhtemelen Sixteen Otto'nun cevabını düşünmelisiniz.


10

Uyarıları reddetmek için bir sıfırdan geçtim, belki bu senin için işe yarar?

NSLog (myString, nil);


5
İkinci paramente uyarıyı çözerken NEDEN sıfır geçmenin uyarıyı çözdüğü açıklanabilir mi?
cprcrack

1
İkinci bir parametrenin olmaması açıkken nil geçmek açıktır. Evden çıkarken şöminenizin yanmadığını varsayabilir veya yanmadığından emin olabilirsiniz. Genellikle şöminenizi nadiren kullandığınız için hiçbir şey olmamakla birlikte, eviniz bir kez yandığında olacaktır.

1
@SoldOutActivist Yararsızdır. Buradaki bariz olmayan nokta (C geçmişinden gelmeyen biri için), açık bir sıfır atmak ile hiçbir şeyi iletmemek arasındaki davranış farkının ne olduğudur ve yorumunuz bunu açıklamıyor.
Mark Amery

İnce: Değişken sayıda bağımsız değişken kabul edebilen her şey Obj-C yöntemi açıkça sonlandırılmamalıdır. Hiçbir şeyi geçmek, sıfır geçmekle aynı şey değildir. Obj-C ile istediğiniz zaman geçirin ve bunu defalarca göreceksiniz. Yapı dizileri en yaygın olanıdır.

3
Bu, derleyici uyarısını durdurabilir, ancak Jon Hess tarafından açıklanan temel sorun hala mevcuttur - içinde birden fazla biçim belirticisi varsa myString, birincisi iyi olur, ancak ikincisi yığındaki çöpü toplar. İkame listesi NSLog()olduğunu asla nil @Sold, nihayetti. Argümanlar listesinin ne kadar uzun olduğunu bulmak için iki seçenek vardır: bir sentinel değer veya ne kullanıldığı printf()ve family - sayının hesaplanmasına izin veren başka bir argüman (örneğin, format belirticilerini sayarak).
jscs

3

"Biçim bir dizge değil ve biçim bağımsız değişkeni değil" uyarısından bir kez ve herkes için kurtulmak istiyorsanız, hedefinizin derleme ayarlarında "Typecheck Calls to printf / scanf" (GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = NO) GCC uyarı ayarını devre dışı bırakabilirsiniz.


5
Bu, uyarıyı susturur, ancak uygulamanızdaki temeldeki kusuru düzeltmek için hiçbir şey yapmaz. Uyarıyı susturarak, yalnızca kullanıcı tarafından girilen verilere (veya bu durumda CoreData tarafından oluşturulan hata mesajına) dayalı olarak uygulamanızı çökertebilecek olası bir hatayı görmezden geliyorsunuz. Uyarının görünmesine neden olan kaynak koddaki hatayı gidermek için bu sorudaki diğer yanıtlardan bazılarını takip etmek daha iyi olacaktır.
Christopher Fairbairn

2
Doğru ... Bu yüzden "çöz" yerine "kurtul uyarısı" yazdım.
aldi

Uthash kitaplığının, utstring_printf işlevine yapılan çağrılarda bu uyarıyı tetiklediği bir durumla karşılaştım, bu nedenle uyarının yanlış olduğu durumlarda bu yararlıdır.
alfwatt

2

NSLog () bir biçim dizesi bekler, iletilen sadece bir dizedir. StringWithFormat: kullanmanız gerekmez, sadece şunları yapabilirsiniz:

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

Ve bu uyarının ortadan kalkmasına neden olur.


2

FWIW, bu iPhone devi için de geçerlidir. 3.1.3 SDK'ya karşı kod yazıyorum ve aynı hatayı aynı sorunla aldım (stringWithFormat'ı NSLog () içine yerleştirme). Sixten ve Jon para peşinde.


0

Sadece herhangi birinin appendFormaton NSMutableString'i kullandığını bilmesini sağlamak , aşağıdaki gibi biçimlendirilmiş bir dizede geçmeye çalışırken de bu uyarının görünmesine neden olabilir:

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

Bu uyarıdan kaçınmak için yukarıdakileri şuna çevirin:

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

Daha özlü ve daha güvenli. Zevk almak!


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

1
stringWithFormatSadece yapabileceğiniz zaman burada kullanmak gereksizdirNSLog(@"%@ %@, %@", errorMsgFormat, error, [error userInfo])
Mark Amery
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.