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?
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?
"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 (meskipun printf("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 dalam 1["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)
1 Prioritas di antara aturan sintaks terjemahan ditentukan oleh fase berikut. 6)
- Token literal string yang berdekatan digabungkan.
Dan baru setelah itu
- Karakter spasi putih yang memisahkan token tidak lagi signifikan. Setiap token pemrosesan awal diubah menjadi token. Token yang dihasilkan dianalisis secara sintaksis dan semantik dan diterjemahkan sebagai unit terjemahan .
Dalam konstruksi ini
"Hi" (test ? "Bye" : "Goodbye")
tidak ada token literal string yang berdekatan. Jadi konstruksi ini tidak valid.
(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:
Token literal string yang berdekatan digabungkan.
terjadi dalam fase penerjemahan . Di samping itu:
printf("Hi" (test ? "Bye" : "Goodbye"));
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:
char *strcat(char * restrict s1,const char * restrict s2);
The
strcat()
Fungsi menambahkan salinan string yang ditunjukkan olehs2
(termasuk terminating nol karakter) sampai akhir dari string yang ditunjukkan olehs1
. Karakter awals2
menimpa karakter nol di akhirs1
. [...]
Jadi, kita bisa lihat, itu s1
adalah string , bukan string literal . Namun, karena konten s2
tidak diubah dengan cara apa pun, ini bisa menjadi string literal .
strcat
: larik tujuan harus cukup panjang untuk menerima karakter dari s2
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
.
Karena C tidak memiliki string
tipe. Literal string dikompilasi menjadi char
array, direferensikan oleh char*
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:
int main() {
static const char char_ptr_1[] = {'H', 'i', 'B', 'y', 'e', '\0'};
printf(char_ptr_1);
}
Perhatikan bagaimana dua string digabungkan menjadi satu array statis oleh kompilator, sebelum program dijalankan.
Namun, contoh kedua Anda "diterjemahkan" menjadi seperti ini:
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));
}
Harus jelas mengapa ini tidak dapat dikompilasi. Operator terner ?
dievaluasi pada waktu proses, bukan waktu kompilasi, ketika "string" tidak lagi ada, tetapi hanya sebagai char
array sederhana , yang direferensikan oleh char*
pointer. Tidak seperti literal string yang berdekatan , pointer char yang berdekatan hanyalah kesalahan sintaksis.
static const char *char_ptr_1 = {'H', 'i', 'B', 'y', 'e', '\0'};
menjadi static const char *char_ptr_1 = "HiBye";
dan juga untuk sisa pointer?
static const char *char_ptr_1 = "HiBye";
kompilator menerjemahkan baris ke static 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'};
sama static const char str[] = "test";
, static const char* ptr = "test";
adalah tidak sama dengan static 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.
#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;
}
Apa alasan untuk itu?
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 untuk printf
. Meski begitu, printf()
hasil cetak akan memberikan kesan "telah menggabungkan" string tersebut hanya pada, dan sedini runtime .
#include <stdio.h>
int main() {
int test = 0;
printf("Hi %s\n", (test ? "Bye" : "Goodbye")); //specify format and print as result
}
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.
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")
(test)? "str1" : "str2"
BUKAN const char*
... Tentu saja! Ini bukan ekspresi konstan, tetapi tipenya adalah const char *
. Tidak masalah untuk menulis printf(test ? "hi " "yes" : "hi " "no")
. Masalah OP tidak ada hubungannya dengan printf
, "Hi" (test ? "Bye" : "Goodbye")
adalah kesalahan sintaks tidak peduli apa konteks ekspresi.
Ini tidak dapat dikompilasi karena daftar parameter untuk fungsi printf adalah
(const char *format, ...)
dan
("Hi" (test ? "Bye" : "Goodbye"))
tidak sesuai dengan daftar parameter.
gcc mencoba memahaminya dengan membayangkannya
(test ? "Bye" : "Goodbye")
adalah daftar parameter, dan mengeluh bahwa "Hi" bukanlah sebuah fungsi.
printf()
daftar argumen, tetapi itu karena ekspresi tidak valid di mana pun - tidak hanya dalam printf()
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 ke printf()
. Saya sarankan Anda menghapus jawaban ini sebelum ditolak.