2014-06-12 36 views
5

GLib hakkında basit bir sorum var.Neden GLib bu işlevlerde 'const' kullanıyor?

static const char *words[] = { "one", "two", "three", NULL }; 

void main() { 
    puts(g_strjoinv("+", words)); 
} 

Bu kod baskılar one+two+three:

Aşağıdaki kod var. Dizeleri birleştiren bir GLib işlevi kullanır. Bu işlevin

signature geçerli:

char *g_strjoinv (const char *separator, char **str_array); 

(. Tam olarak, GLib değil char, gchar kullanır ama en bu görmezden let)

Şimdi, parametredir neden acaba char **str_array ve const char **str_array. Bu derleyici'nın uyarısı kurtulmak için açık döküm yapmamı zorlar (" 'char **' ama argüman '** const char' tiptedir beklenen"):

puts(g_strjoinv("+", (char **)words)); 

Ben GLib's reference ve I bakmak tüm işlevlerinin şu şekilde tanımlandığını görürsünüz: char **, const char ** değil.

Neden? Neden GLIB const char ** kullanıyor?

Yapıdan kurtulmak için açık bir döküm kullanmanız gerekiyorsa, kodum daha az güvenlidir (çünkü derleyici, argümanların uyumluluğunu artık kontrol etmemektedir). Ayrıca beni tedirgin ediyor çünkü GLib veriyi değiştirmeyeceğini söyleyen bir sözleşme imzalamıyor.

+1

Harika bir soru, str_array kesinlikle değişmez (?), Bu durumda const anlamlı olur. – this

+0

@self: Evet, ve bu sadece bir fonksiyonla ilgili bir problem değil. Bir dizi dizgiyi kabul eden GLib'in * tümünde * vardır. Bunu yapmak için iyi bir sebebi var sanırım ve ne olduğunu bilmek istiyorum. –

+3

[Bu soruya] bakmak isteyebilirsiniz (http://c-faq.com/ansi/constmismatch.html). Eğer normal bir “char **” olsaydı, bu mümkün olmazsa, onu “const char **” bekleyen bir işleve çeviremezdiniz, böylece bir problemi çözemezdiniz. bunu beyan ediyor. –

cevap

6

sorunuzu varsayım g_strjoinv() ikinci argüman türü const char ** olarak ilan edilmiştir, o zaman aynı kolaylıkla geçebilir olmasıdır ya bir const char ** veya ona bir char **.

Maalesef, bu doğru değil. this question from the comp.lang.c FAQ'da açıklandığı gibi, T işaretçisini kullanarak (T herhangi bir tür için) const T işaretçisinin beklenmesi yeterlidir, ancak yalnızca uyumsuzluğun en üst düzeyde olduğu durumlarda. Yani, bir char *'u const char *'un beklendiği bir yerden geçirebilirsiniz, ancak bir char **'u const char **'un beklemesi gereken bir geçiş yapamazsınız, çünkü bu durumda uyumsuzluk ikinci düzeydeki dolaylılık düzeyindedir. Bağlantılı soru, bazı detaylarda niçin'un bu şekilde çalıştığını açıklamaktadır, ki bu "biraz belirsiz" dir.

Bu nedenle, en az bir tane olmaksızın bir char ** ve const char ** kabul edecek tür (C cinsinden) yoktur. Bu durumda, kolaylıktan başka birini tercih etmek için pek fazla sebep yoktur ve kütüphane yazarları görünüşe göre eski ile gitmeye karar vermişlerdir. Saf bir spekülasyon meselesi olarak, bir char **'u geçmek isteyenlerin bir const char **'u geçmek istemekten biraz daha yaygın olduğunu tahmin ediyorum, ve böylece seçtikleri seçenek muhtemelen daha uygun.

Sizin durumunuzda, const niteleyiciyi dizininizin tanımına bırakabilirsiniz.const'dan hoşlanıyorsanız, kötü bir biçim gibi görünebilir, ancak dize değişmezlerine işaret eden bir dizi işaretçiniz olduğundan, programınız her ne kadar bir şey yazılmaya çalışılırsa yüksek sesle şikayetçi ve başarısız olur. Bu özel durumda güvenliği gerçekten anlamlı bir şekilde kaybetmek. Onları değiştirmeye çalışmak için tanımlanmamış bir davranış olsa da, dize değişmezleri, const char dizisi (C++'dan farklı olarak), C cinsinden char tür dizisine sahiptir.

Biraz daha belirsiz, ancak const char ** olarak iletebilseniz bile, buradaki işlev, işaret ettikleri şeyi değiştiremese bile işaretçileri değiştirebilir ve farklı bir şekilde kargaşaya neden olabilir. Yapılan işlevin bir başka deyişle, işleve ilettiğiniz şeyin bir şekilde değiştirilemeyeceğini garanti etmez.

+0

Bu bir ** mükemmel ** cevap, çok teşekkür ederim! Bu sorunu daha önce de görmüştüm ama bu mevcut dava ile ilgili olduğunu bilmiyordum. Şimdi, teşekkürler, tamamen anlıyorum. BTW, sen benim "const" u bırakabileceğimi söylüyorsun, ama bunu yaptığımda GCC beni uyarır ("initialization 'const' consts ..."), üstelik sanırım, dizge değişmezlerini sabit olarak görür. –

+0

(BTW, son paragraf için teşekkürler. C becerilerim biraz paslı ve bu düzeltmeye ihtiyacım vardı.) –

+0

Bu, sahte bir uyarı gibi geliyor, bunu C++ olarak veya bazı uzatma ayarlarıyla derlemediğinizden emin misiniz? ? Standart C olarak derlemek size bu uyarıyı vermemelidir. –

İlgili konular