Kode berikut dikompilasi tanpa masalah:
int main() {
printf("Hi" "Bye");
}
Namun, ini tidak dapat dikompilasi:
int main() {
int test = 0;
printf("Hi" (test ? "Bye" : "Goodbye"));
}
Apa alasan untuk itu?
c
string
syntax
concatenation
conditional-operator
José D.
sumber
sumber
"Hi"
dan"Bye"
adalah string literal , bukan string seperti yang digunakan di pustaka standar C. Dengan string literal , kompilator akan menggabungkan"H\0i" "B\0ye"
. Tidak sama dengansprintf(buf,"%s%s", "H\0i" "B\0ye");
a (some_condition ? + : - ) b
printf("Hi" ("Bye"));
tidak akan berfungsi - tidak memerlukan operator terner; tanda kurung cukup (meskipunprintf("Hi" test ? "Bye" : "Goodbye")
juga tidak dapat dikompilasi). Hanya ada sejumlah token yang dapat mengikuti literal string. Tanda koma,
, kurung kotak terbuka, kurung kotak[
dekat]
(seperti dalam1["abc"]
- dan ya, itu mengerikan), kurung siku)
dekat, kurung kurawal tutup}
(dalam penginisialisasi atau konteks serupa), dan titik koma;
sah (dan string literal lainnya); Saya tidak yakin ada yang lain.Jawaban:
Menurut Standar C (5.1.1.2 fase Terjemahan)
Dan baru setelah itu
Dalam konstruksi ini
tidak ada token literal string yang berdekatan. Jadi konstruksi ini tidak valid.
sumber
(test ? "Bye" : "Goodbye")
mengevakuasi ke salah satu string literal yang pada dasarnya membuat"Hi" "Bye"
atau"Hi Goodbye"
? (pertanyaan saya terjawab di jawaban lain)Sesuai standar C11, bab §5.1.1.2, rangkaian literal string yang berdekatan:
terjadi dalam fase penerjemahan . Di samping itu:
melibatkan operator bersyarat, yang dievaluasi pada waktu proses . Jadi, pada waktu kompilasi, selama fase penerjemahan, tidak ada literal string yang berdekatan, sehingga penggabungan tidak mungkin dilakukan. Sintaksnya tidak valid dan karenanya dilaporkan oleh compiler Anda.
Untuk menguraikan sedikit tentang bagian why , selama fase preprocessing, literal string yang berdekatan digabungkan dan direpresentasikan sebagai literal string tunggal (token). Penyimpanan dialokasikan sesuai dan literal string yang digabungkan dianggap sebagai entitas tunggal (satu string literal).
Di sisi lain, dalam kasus run-time concatenation, tujuan harus memiliki cukup memori untuk menampung string literal yang digabungkan jika tidak, tidak akan ada cara agar output gabungan yang diharapkan dapat diakses. Sekarang, dalam kasus literal string , mereka sudah dialokasikan memori pada waktu kompilasi dan tidak dapat diperpanjang agar sesuai dengan masukan yang masuk atau ditambahkan ke konten asli. Dengan kata lain, tidak mungkin hasil gabungan dapat diakses (disajikan) sebagai literal string tunggal . Jadi, konstruksi ini secara inheren salah.
Sebagai informasi, untuk rangkaian run-time ( bukan literal ), kami memiliki fungsi library
strcat()
yang menggabungkan dua string . Perhatikan, deskripsi menyebutkan:Jadi, kita bisa lihat, itu
s1
adalah string , bukan string literal . Namun, karena kontens2
tidak diubah dengan cara apa pun, ini bisa menjadi string literal .sumber
strcat
: larik tujuan harus cukup panjang untuk menerima karakter daris2
ditambah terminator null setelah karakter sudah ada di sana.Rangkaian literal string dilakukan oleh preprocessor pada waktu kompilasi. Tidak ada cara untuk penggabungan ini untuk mengetahui nilai dari
test
, yang tidak diketahui sampai program benar-benar dijalankan. Oleh karena itu, literal string ini tidak dapat digabungkan.Karena kasus umumnya adalah Anda tidak akan memiliki konstruksi seperti ini untuk nilai yang diketahui pada waktu kompilasi, standar C dirancang untuk membatasi fitur penggabungan otomatis ke kasus yang paling dasar: ketika literal benar-benar tepat berdampingan satu sama lain .
Tetapi bahkan jika itu tidak menyebutkan batasan ini dengan cara itu, atau jika batasan itu dibangun secara berbeda, contoh Anda masih tidak mungkin untuk diwujudkan tanpa membuat penggabungan sebagai proses runtime. Dan, untuk itu, kami memiliki fungsi perpustakaan seperti
strcat
.sumber
Karena C tidak memiliki
string
tipe. Literal string dikompilasi menjadichar
array, direferensikan olehchar*
pointer.C memungkinkan literal yang berdekatan untuk digabungkan pada waktu kompilasi , seperti pada contoh pertama Anda. Kompilator C sendiri memiliki beberapa pengetahuan tentang string. Tetapi informasi ini tidak ada pada waktu proses, dan karenanya penggabungan tidak dapat terjadi.
Selama proses kompilasi, contoh pertama Anda "diterjemahkan" ke:
Perhatikan bagaimana dua string digabungkan menjadi satu array statis oleh kompilator, sebelum program dijalankan.
Namun, contoh kedua Anda "diterjemahkan" menjadi seperti ini:
Harus jelas mengapa ini tidak dapat dikompilasi. Operator terner
?
dievaluasi pada waktu proses, bukan waktu kompilasi, ketika "string" tidak lagi ada, tetapi hanya sebagaichar
array sederhana , yang direferensikan olehchar*
pointer. Tidak seperti literal string yang berdekatan , pointer char yang berdekatan hanyalah kesalahan sintaksis.sumber
static const char *char_ptr_1 = {'H', 'i', 'B', 'y', 'e', '\0'};
menjadistatic const char *char_ptr_1 = "HiBye";
dan juga untuk sisa pointer?static const char *char_ptr_1 = "HiBye";
kompilator menerjemahkan baris kestatic const char *char_ptr_1 = {'H', 'i', 'B', 'y', 'e', '\0'};
, jadi tidak, itu tidak boleh ditulis "seperti string". Seperti yang dikatakan Answer, string dikompilasi menjadi array karakter, dan jika Anda menetapkan array karakter dalam bentuk paling "mentah", Anda akan menggunakan daftar karakter yang dipisahkan koma, sepertistatic const char *char_ptr_1 = {'H', 'i', 'B', 'y', 'e', '\0'};
static const char str[] = {'t', 'e', 's', 't', '\0'};
samastatic const char str[] = "test";
,static const char* ptr = "test";
adalah tidak sama denganstatic const char* ptr = {'t', 'e', 's', 't', '\0'};
. Yang pertama valid dan akan dikompilasi tetapi yang terakhir tidak valid dan melakukan apa yang Anda harapkan.Jika Anda benar-benar ingin kedua cabang menghasilkan konstanta string waktu kompilasi untuk dipilih saat runtime, Anda memerlukan makro.
sumber
Kode Anda menggunakan operator terner secara bersyarat memilih antara dua literal string. Terlepas dari kondisi yang diketahui atau tidak diketahui, ini tidak dapat dievaluasi pada waktu kompilasi, sehingga tidak dapat dikompilasi. Bahkan pernyataan ini
printf("Hi" (1 ? "Bye" : "Goodbye"));
tidak dapat dikompilasi. Alasannya dijelaskan secara mendalam pada jawaban di atas. Kemungkinan lain untuk membuat pernyataan seperti itu menggunakan operator terner valid untuk dikompilasi , juga akan melibatkan tag format dan hasil dari pernyataan operator terner diformat sebagai argumen tambahan untukprintf
. Meski begitu,printf()
hasil cetak akan memberikan kesan "telah menggabungkan" string tersebut hanya pada, dan sedini runtime .sumber
printf
tidak membutuhkan penentu format; jika hanya penggabungan dilakukan pada waktu kompilasi (yang sebenarnya tidak), penggunaan printf oleh OP akan valid.printf()
akan membutuhkan tag format, yang sama sekali tidak benar. Diperbaiki!Dalam
printf("Hi" "Bye");
Anda memiliki dua array berturut-turut char yang kompilator dapat membuat menjadi array tunggal.Di
printf("Hi" (test ? "Bye" : "Goodbye"));
Anda memiliki satu array diikuti oleh pointer ke char (array diubah menjadi pointer ke elemen pertamanya). Kompiler tidak dapat menggabungkan array dan pointer.sumber
Untuk menjawab pertanyaan - saya akan pergi ke definisi printf. Fungsi printf mengharapkan const char * sebagai argumen. Setiap string literal seperti "Hi" adalah sebuah const char *; namun ekspresi seperti
(test)? "str1" : "str2"
BUKAN sebuah const char * karena hasil dari ekspresi tersebut hanya ditemukan pada saat run-time dan oleh karena itu tidak dapat ditentukan pada waktu kompilasi, sebuah fakta yang menyebabkan compiler mengeluh. Di sisi lain - ini bekerja dengan baikprintf("hi %s", test? "yes":"no")
sumber
(test)? "str1" : "str2"
BUKANconst char*
... Tentu saja! Ini bukan ekspresi konstan, tetapi tipenya adalahconst char *
. Tidak masalah untuk menulisprintf(test ? "hi " "yes" : "hi " "no")
. Masalah OP tidak ada hubungannya denganprintf
,"Hi" (test ? "Bye" : "Goodbye")
adalah kesalahan sintaks tidak peduli apa konteks ekspresi.Ini tidak dapat dikompilasi karena daftar parameter untuk fungsi printf adalah
dan
tidak sesuai dengan daftar parameter.
gcc mencoba memahaminya dengan membayangkannya
adalah daftar parameter, dan mengeluh bahwa "Hi" bukanlah sebuah fungsi.
sumber
printf()
daftar argumen, tetapi itu karena ekspresi tidak valid di mana pun - tidak hanya dalamprintf()
daftar argumen. Dengan kata lain, Anda telah memilih alasan yang terlalu khusus untuk masalah tersebut; masalah umumnya"Hi" (
adalah tidak valid di C, apalagi di panggilan keprintf()
. Saya sarankan Anda menghapus jawaban ini sebelum ditolak.