Aşağıdaki kod sorunsuz bir şekilde derlenir:
int main() {
printf("Hi" "Bye");
}
Ancak, bu derlemez:
int main() {
int test = 0;
printf("Hi" (test ? "Bye" : "Goodbye"));
}
Bunun nedeni nedir?
Aşağıdaki kod sorunsuz bir şekilde derlenir:
int main() {
printf("Hi" "Bye");
}
Ancak, bu derlemez:
int main() {
int test = 0;
printf("Hi" (test ? "Bye" : "Goodbye"));
}
Bunun nedeni nedir?
"Hi"
ve "Bye"
vardır dize hazır değil dizeleri C standart kütüphanesinde kullanılan. İle dizgilerin , derleyici sıralamak olacak "H\0i" "B\0ye"
. Aynı değilsprintf(buf,"%s%s", "H\0i" "B\0ye");
a (some_condition ? + : - ) b
printf("Hi" ("Bye"));
çalışmayacağına dikkat edin - üçlü operatör gerektirmez; parantez yeterlidir (ancak printf("Hi" test ? "Bye" : "Goodbye")
derlenmez). Bir dizge hazır bilgisini takip edebilecek yalnızca sınırlı sayıda simge vardır. Virgül ,
, açık köşeli parantez [
, köşeli parantezi kapat ]
(olduğu gibi 1["abc"]
- ve evet, dehşet verici), yuvarlak parantezi )
kapat, kıvrımlı parantezi kapat }
(bir başlatıcı veya benzer bağlamda) ve noktalı virgül ;
meşru (ve başka bir dize hazır); Başkalarının olduğundan emin değilim.
Yanıtlar:
C Standardına göre (5.1.1.2 Çeviri aşamaları)
1 Çeviri sözdizimi kuralları arasındaki öncelik, aşağıdaki aşamalarla belirlenir.6)
- Bitişik dize değişmez belirteçleri birleştirilir.
Ve sadece ondan sonra
- Jetonları ayıran beyaz boşluk karakterleri artık önemli değil. Her ön işleme jetonu bir jetona dönüştürülür. Ortaya çıkan simgeler sözdizimsel ve anlamsal olarak analiz edilir ve bir çeviri birimi olarak çevrilir .
Bu inşaatta
"Hi" (test ? "Bye" : "Goodbye")
bitişik dize değişmez belirteçleri yoktur. Yani bu yapı geçersizdir.
(test ? "Bye" : "Goodbye")
dize hazır birine değerlendiririz esasen yapma "Hi" "Bye"
ya "Hi Goodbye"
? (sorum diğer cevaplarda cevaplandı)
C11 standardına göre, bölüm §5.1.1.2, bitişik dize değişmezlerinin birleştirilmesi:
Bitişik dize değişmez belirteçleri birleştirilir.
olur dönüşüm aşamasından . Diğer yandan:
printf("Hi" (test ? "Bye" : "Goodbye"));
çalışma zamanında değerlendirilen koşullu operatörü içerir . Bu nedenle, derleme sırasında, çeviri aşamasında, bitişik dizeler mevcut değildir, dolayısıyla birleştirme mümkün değildir. Sözdizimi geçersizdir ve bu nedenle derleyiciniz tarafından rapor edilir.
Neden bölümünde biraz ayrıntı vermek için , ön işleme aşaması sırasında, bitişik dize değişmezleri birleştirilir ve tek bir dize değişmezi (jeton) olarak temsil edilir . Depolama buna göre tahsis edilir ve birleştirilmiş dize değişmezi tek bir varlık (bir dize değişmezi) olarak kabul edilir .
Öte yandan, çalışma zamanı birleştirme durumunda, hedef, birleştirilmiş dizeyi sabit tutmaya yetecek kadar belleğe sahip olmalıdır, aksi takdirde, beklenen birleştirilmiş çıktıya erişilemeyecektir. Şimdi, söz konusu dize hazır , onlar zaten derleme sırasında bellek tahsis edilir ve olamaz genişletilmiş bir daha gelen girişteki uyum için içine veya eklenen orijinal içerik. Başka bir deyişle, birleştirilmiş sonuca tek bir dize hazır bilgisi olarak erişilmesi (sunulması) mümkün olmayacaktır . Dolayısıyla, bu yapı doğası gereği yanlıştır.
Bilginize, çalışma zamanı dizesi ( değişmez değerler değil ) birleştirme için, strcat()
iki dizeyi birleştiren kitaplık işlevine sahibiz . Dikkat, açıklama şunlardan bahsediyor:
char *strcat(char * restrict s1,const char * restrict s2);
strcat()
Fonksiyon ile gösterilen dizinin bir kopyasını eklers2
sonuna (sonlandırıcı boş karakter dahil) dizesi tarafından işarets1
. İlk karakters2
sonundaki boş karakterin üzerine yazars1
. [...]
Böylece, s1
bir dizge olduğunu görebiliriz, değişmez bir dize değil . Bununla birlikte, içeriği s2
herhangi bir şekilde değiştirilmediğinden, çok iyi bir dizge olabilir .
strcat
: hedef dizi, karakterleri s2
artı orada zaten mevcut olan karakterlerden sonra bir boş sonlandırıcı alacak kadar uzun olmalıdır .
Dize değişmez birleştirme, derleme zamanında önişlemci tarafından gerçekleştirilir. Bu birleştirmenin test
, program fiilen çalıştırılıncaya kadar bilinmeyen değerinden haberdar olmasının bir yolu yoktur . Bu nedenle, bu dize değişmezleri birleştirilemez.
Genel durum, derleme zamanında bilinen değerler için böyle bir yapıya sahip olmayacağınızdan, C standardı, otomatik birleştirme özelliğini en temel durumla sınırlandırmak için tasarlanmıştır: değişmez değerler birbirinin yanında tam anlamıyla doğru olduğunda .
Ancak bu kısıtlamayı bu şekilde ifade etmemiş olsa veya kısıtlama farklı bir şekilde oluşturulmuş olsa bile, birleştirme işlemini bir çalışma zamanı süreci yapmadan örneğinizin gerçekleştirilmesi yine de imkansız olacaktır. Ve bunun için, gibi kütüphane işlevlerine sahibiz strcat
.
Çünkü C'nin string
tipi yoktur . Dize değişmezleri, char
bir char*
işaretçi tarafından başvurulan dizilere derlenir .
C, ilk örneğinizde olduğu gibi , bitişik değişmez değerlerin derleme zamanında birleştirilmesine izin verir . C derleyicisinin kendisi dizeler hakkında biraz bilgi sahibidir. Ancak bu bilgi çalışma zamanında mevcut değildir ve bu nedenle birleştirme gerçekleşemez.
Derleme işlemi sırasında, ilk örneğiniz şu dile "çevrilir":
int main() {
static const char char_ptr_1[] = {'H', 'i', 'B', 'y', 'e', '\0'};
printf(char_ptr_1);
}
Program çalıştırılmadan önce, iki dizenin derleyici tarafından tek bir statik dizide nasıl birleştirildiğine dikkat edin.
Ancak, ikinci örneğiniz şöyle bir şeye "çevrilir":
int main() {
static const char char_ptr_1[] = {'H', 'i', '\0'};
static const char char_ptr_2[] = {'B', 'y', 'e', '\0'};
static const char char_ptr_3[] = {'G', 'o', 'o', 'd', 'b', 'y', 'e', '\0'};
int test = 0;
printf(char_ptr_1 (test ? char_ptr_2 : char_ptr_3));
}
Bunun neden derlenmediği açık olmalıdır. Üçlü operatör ?
, "dizeler" artık mevcut olmadığında, yalnızca işaretçiler char
tarafından başvurulan basit diziler olarak mevcut olduğunda derleme zamanında değil, çalışma zamanında değerlendirilir char*
. Bitişik dize değişmezlerinin aksine , bitişik karakter işaretçileri sadece bir sözdizimi hatasıdır.
static const char *char_ptr_1 = {'H', 'i', 'B', 'y', 'e', '\0'};
olmak static const char *char_ptr_1 = "HiBye";
ve benzer işaretçiler geri kalanı için?
static const char *char_ptr_1 = "HiBye";
, derleyici satırı 'ye çevirir static const char *char_ptr_1 = {'H', 'i', 'B', 'y', 'e', '\0'};
, bu yüzden hayır, "bir dizge gibi" yazılmamalıdır . Cevap söylediği gibi dizeleri karakterlerin dizisi için derlenmektedir ve bunu en "ham" şeklinde karakter dizisi atama olsaydı, tıpkı bir virgül karakter listesi ayrılmış kullanırsınızstatic const char *char_ptr_1 = {'H', 'i', 'B', 'y', 'e', '\0'};
static const char str[] = {'t', 'e', 's', 't', '\0'};
aynıdır static const char str[] = "test";
, static const char* ptr = "test";
olduğu değil aynı static const char* ptr = {'t', 'e', 's', 't', '\0'};
. İlki geçerlidir ve derlenecektir, ancak ikincisi geçersizdir ve beklediğinizi yapar.
Her iki dalın da çalışma zamanında seçilecek derleme zamanı dize sabitleri üretmesini gerçekten istiyorsanız, bir makroya ihtiyacınız olacaktır.
#include <stdio.h>
#define ccat(s, t, a, b) ((t)?(s a):(s b))
int
main ( int argc, char **argv){
printf("%s\n", ccat("hello ", argc > 2 , "y'all", "you"));
return 0;
}
Bunun nedeni nedir?
Üçlü operatör kullanan kodunuz koşullu olarak iki değişmez dize arasında seçim yapar. Bilinen veya bilinmeyen koşul ne olursa olsun, bu derleme zamanında değerlendirilemez, bu yüzden derleme yapamaz. Bu ifade bile printf("Hi" (1 ? "Bye" : "Goodbye"));
derlenmez. Nedeni, yukarıdaki cevaplarda derinlemesine açıklanmıştır. Bir başka olasılık derlemek için üçlü operatörü geçerli kullanarak bu tür bir açıklama yaparak , aynı zamanda bir yer alacağı format etiketi ve biçimlendirilmiş üçlü operatör ifadesinin sonucunu ek argüman için printf
. O zaman bile, printf()
çıktı bu dizeleri yalnızca çalışma zamanında ve bu kadar erken bir zamanda "birleştirmiş" izlenimi verirdi .
#include <stdio.h>
int main() {
int test = 0;
printf("Hi %s\n", (test ? "Bye" : "Goodbye")); //specify format and print as result
}
printf
vermez gerektiren bir format tanımlayıcı; derleme zamanında sadece birleştirme yapılsaydı (ki bu değildir), OP'nin printf kullanımı geçerli olacaktır.
printf()
bir biçim etiketi gerektiriyormuş gibi görünecek , ki bu kesinlikle doğru değil. Düzeltildi!
İçinde printf("Hi" "Bye");
, derleyicinin tek bir dizi haline getirebileceği iki ardışık karakter dizisine sahipsiniz.
İçinde printf("Hi" (test ? "Bye" : "Goodbye"));
bir dizi ve onu izleyen bir işaretçi (ilk elemanına bir göstericiye dönüştürülmüş bir dizi) var. Derleyici bir dizi ve bir işaretçiyi birleştiremez .
Soruyu cevaplamak için - printf'in tanımına gidecektim. Printf işlevi argüman olarak const char * olmasını bekler . "Hi" gibi herhangi bir dizge sabit bir karakterdir *; ancak böyle bir ifade (test)? "str1" : "str2"
sabit karakter * DEĞİLDİR çünkü böyle bir ifadenin sonucu yalnızca çalışma zamanında bulunur ve dolayısıyla derleme zamanında belirsizdir, bu da derleyicinin gerektiği gibi şikayet etmesine neden olan bir gerçektir. Öte yandan - bu mükemmel bir şekilde çalışıyorprintf("hi %s", test? "yes":"no")
(test)? "str1" : "str2"
DEĞİL const char*
... Tabii ki öyle! Sabit bir ifade değildir, ancak türü öyledir const char *
. Yazmak son derece iyi olurdu printf(test ? "hi " "yes" : "hi " "no")
. OP'ın problemi ile ilgisi vardır printf
, "Hi" (test ? "Bye" : "Goodbye")
ne olursa olsun ifade bağlamının ne bir yazım hatasıdır.
Bu derlenmez çünkü printf işlevi için parametre listesi
(const char *format, ...)
ve
("Hi" (test ? "Bye" : "Goodbye"))
parametre listesine uymuyor.
gcc bunu hayal ederek anlamlandırmaya çalışır
(test ? "Bye" : "Goodbye")
bir parametre listesidir ve "Hi" nin bir işlev olmadığından şikayet eder.
printf()
Argüman listesiyle eşleşmediği konusunda haklısınız , ancak bunun nedeni ifadenin hiçbir yerde geçerli olmamasıdır - sadece printf()
argüman listesinde değil. Başka bir deyişle, sorun için çok fazla özel bir neden seçtiniz; genel sorun, "Hi" (
bir çağrı bir yana, C de geçerli olmamasıdır printf()
. Bu yanıtı olumsuz oylamadan önce silmenizi öneririm.