Saya memiliki program sederhana ini:
#include <stdio.h>
struct S
{
int i;
};
void swap(struct S *a, struct S *b)
{
struct S temp;
temp = *a /* Oops, missing a semicolon here... */
*a = *b;
*b = temp;
}
int main(void)
{
struct S a = { 1 };
struct S b = { 2 };
swap(&a, &b);
}
Seperti yang terlihat di eg ideone.com ini memberikan kesalahan:
prog.c: In function 'swap': prog.c:12:5: error: invalid operands to binary * (have 'struct S' and 'struct S *') *a = *b; ^
Mengapa kompilator tidak mendeteksi titik koma yang hilang?
Catatan: Pertanyaan ini dan jawabannya dimotivasi oleh pertanyaan ini . Meskipun ada pertanyaan lain yang serupa dengan ini, saya tidak menemukan apa pun yang menyebutkan kapasitas bentuk bebas dari bahasa C yang menyebabkan ini dan kesalahan terkait.
Jawaban:
C adalah bahasa bentuk bebas . Itu berarti Anda dapat memformatnya dengan banyak cara dan itu akan tetap menjadi program yang legal.
Misalnya pernyataan seperti
bisa ditulis seperti
atau suka
Jadi ketika kompiler melihat garis
menurutnya itu berarti
Itu tentu saja bukan ekspresi yang valid dan kompilator akan mengeluh tentang hal itu alih-alih titik koma yang hilang. Alasan tidak valid adalah karena
a
merupakan pointer ke struktur, jadi*a * a
mencoba mengalikan struktur instance (*a
) dengan pointer ke struktur (a
).Meskipun kompilator tidak dapat mendeteksi titik koma yang hilang, ia juga melaporkan kesalahan yang sama sekali tidak terkait pada baris yang salah. Ini penting untuk diperhatikan karena tidak peduli seberapa banyak Anda melihat baris di mana kesalahan dilaporkan, tidak ada kesalahan di sana. Terkadang masalah seperti ini mengharuskan Anda untuk melihat baris sebelumnya untuk melihat apakah mereka baik-baik saja dan tanpa kesalahan.
Terkadang Anda bahkan harus melihat file lain untuk menemukan kesalahannya. Misalnya jika file header menentukan struktur yang terakhir dilakukan di file header, dan titik koma yang mengakhiri struktur tidak ada, maka kesalahan tidak akan ada di file header tetapi di file yang menyertakan file header.
Dan terkadang menjadi lebih buruk: jika Anda menyertakan dua (atau lebih) file header, dan yang pertama berisi deklarasi yang tidak lengkap, kemungkinan besar kesalahan sintaks akan ditunjukkan di file header kedua.
Terkait hal ini adalah konsep kesalahan tindak lanjut . Beberapa kesalahan, biasanya karena titik koma hilang, dilaporkan sebagai beberapa kesalahan. Inilah mengapa penting untuk memulai dari atas saat memperbaiki kesalahan, karena memperbaiki kesalahan pertama mungkin membuat beberapa kesalahan hilang.
Hal ini tentu saja dapat menyebabkan perbaikan satu kesalahan pada satu waktu dan seringnya mengkompilasi ulang yang dapat merepotkan dengan proyek besar. Mengenali kesalahan tindak lanjut semacam itu adalah sesuatu yang datang dengan pengalaman, dan setelah melihatnya beberapa kali, lebih mudah untuk menggali kesalahan sebenarnya dan memperbaiki lebih dari satu kesalahan per kompilasi ulang.
sumber
temp = *a * a = *b
bisa menjadi ekspresi yang valid jikaoperator*
kelebihan beban. (Namun, pertanyaannya ditandai sebagai "C".)Ada tiga hal yang perlu diingat.
*
di C dapat berupa operator uner dan biner. Sebagai operator unary artinya "dereferensi", sebagai operator biner artinya "perkalian".Hasil dari kedua fakta ini adalah saat kita mengurai.
Yang pertama dan terakhir
*
diartikan sebagai satu tetapi yang kedua*
diartikan sebagai biner. Dari perspektif sintaks, ini terlihat OK.Hanya setelah penguraian ketika kompilator mencoba menafsirkan operator dalam konteks jenis operannya, kesalahan akan terlihat.
sumber
Beberapa jawaban bagus diatas, tapi akan saya uraikan.
Ini sebenarnya adalah kasus di
x = y = z;
mana keduanyax
dany
diberi nilaiz
.Apa yang Anda katakan adalah
the contents of address (a times a) become equal to the contents of b, as does temp
.Singkatnya,
*a *a = <any integer value>
adalah pernyataan yang valid. Seperti disebutkan sebelumnya, yang pertama*
dereferensi penunjuk, sedangkan yang kedua mengalikan dua nilai.sumber
y
bahkan bukan variabel, itu adalah ekspresi*a *a
, dan Anda tidak dapat menetapkan hasil perkalian.Sebagian besar penyusun mengurai file sumber secara berurutan, dan melaporkan baris tempat mereka menemukan ada sesuatu yang salah. 12 baris pertama dari program C Anda bisa menjadi awal dari program C yang valid (bebas kesalahan). 13 baris pertama program Anda tidak bisa. Beberapa kompiler akan mencatat lokasi hal-hal yang mereka temui yang bukan merupakan kesalahan itu sendiri, dan dalam banyak kasus tidak akan memicu kesalahan nanti dalam kode, tetapi mungkin tidak valid jika dikombinasikan dengan yang lain. Sebagai contoh:
Pernyataan
int foo;
itu sendiri akan baik-baik saja. Begitu juga deklarasifloat foo;
. Beberapa kompiler dapat merekam nomor baris di mana deklarasi pertama muncul, dan mengaitkan pesan informasional dengan baris tersebut, untuk membantu programmer mengidentifikasi kasus-kasus di mana definisi sebelumnya sebenarnya salah. Penyusun juga dapat menyimpan nomor baris yang terkait dengan sesuatu seperti ado
, yang dapat dilaporkan jika terkaitwhile
tidak muncul di tempat yang tepat. Untuk kasus di mana kemungkinan lokasi masalah akan tepat sebelum baris di mana kesalahan ditemukan, bagaimanapun, penyusun umumnya tidak repot-repot menambahkan laporan tambahan untuk posisi tersebut.sumber