Derleyici neden eksik bir noktalı virgül bildirmiyor?


115

Bu basit programım var:

#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);
}

Örneğin ideone.com'da görüldüğü gibi bu bir hata verir:

prog.c: In function 'swap':
prog.c:12:5: error: invalid operands to binary * (have 'struct S' and 'struct S *')
     *a = *b;
     ^

Derleyici neden eksik noktalı virgülü algılamıyor?


Not: Bu soru ve cevabı bu soru ile motive edilmektedir . Buna benzer başka sorular olsa da, buna ve ilgili hatalara neden olan C dilinin serbest biçim kapasitesinden bahseden hiçbir şey bulamadım.


16
Bu gönderiyi ne motive etti?
R Sahu

10
@TavianBarnes Keşfedilebilirliği. Bu tür bir sorun aranırken diğer soru keşfedilemez. Bu şekilde düzenlenebilir, ancak bu biraz değiştirmeyi gerektirir ve onu tamamen farklı bir soru IMO haline getirir.
Bir programcı dostum

4
@TavianBarnes: Asıl soru hatayı sormaktı. Bu soru, derleyicinin (en azından OP'ye) neden hatanın yerini yanlış bildirdiğini soruyor.
TonyK

80
Düşünmek için gelin: Bir derleyici eksik noktalı virgülleri sistematik olarak tespit edebiliyorsa, dilin başlamak için noktalı virgüllere ihtiyacı olmaz.
Euro Micelli

5
Derleyicilerin işi hatayı bildirmektir. Hatayı düzeltmek için neyi değiştireceğinizi bulmak sizin işiniz.
David Schwartz

Yanıtlar:


213

C serbest biçimli bir dildir. Bu, onu birçok şekilde biçimlendirebileceğiniz ve yine de yasal bir program olacağı anlamına gelir.

Örneğin şöyle bir ifade

a = b * c;

gibi yazılabilir

a=b*c;

ya da beğen

a
=
b
*
c
;

Yani derleyici satırları gördüğünde

temp = *a
*a = *b;

bunun anlamı olduğunu düşünüyor

temp = *a * a = *b;

Bu elbette geçerli bir ifade değildir ve derleyici eksik noktalı virgül yerine bundan şikayet edecektir. Bunun geçerli olmamasının nedeni a, bir yapıya işaretçi olması, dolayısıyla *a * abir yapı örneğini ( *a) bir yapıya ( a) gösterici ile çarpmaya çalışmaktır .

Derleyici eksik noktalı virgülü algılayamasa da, tamamen ilgisiz hatayı yanlış satırda bildirir. Bunu fark etmek önemlidir, çünkü hatanın bildirildiği satıra ne kadar bakarsanız bakın, orada hata yoktur. Bazen bunun gibi problemlerin iyi olup olmadığını ve hatasız olup olmadığını görmek için önceki satırlara bakmanız gerekir .

Bazen hatayı bulmak için başka bir dosyaya bakmanız bile gerekir. Örneğin, bir başlık dosyası, başlık dosyasında yaptığı son yapıyı tanımlıyorsa ve yapıyı sonlandıran noktalı virgül yoksa, hata başlık dosyasında değil, başlık dosyasını içeren dosyada olacaktır.

Ve bazen daha da kötüleşir: iki (veya daha fazla) başlık dosyası eklerseniz ve ilki eksik bir bildirim içeriyorsa, büyük olasılıkla sözdizimi hatası ikinci başlık dosyasında gösterilecektir.


Bununla ilgili, takip hataları kavramıdır . Genellikle eksik noktalı virgüllerden kaynaklanan bazı hatalar birden çok hata olarak rapor edilir . Bu nedenle, hataları düzeltirken en baştan başlamak önemlidir, çünkü ilk hatayı düzeltmek birden fazla hatayı ortadan kaldırabilir.

Elbette bu, her seferinde bir hatanın düzeltilmesine ve büyük projelerde külfetli olabilen sık tekrar derlemelere yol açabilir. Bu tür takip hatalarını tanımak, deneyimle gelen bir şeydir ve bunları birkaç kez gördükten sonra gerçek hataları ortaya çıkarmak ve yeniden derleme başına birden fazla hatayı düzeltmek daha kolaydır.


16
C ++ temp = *a * a = *b olabilir eğer geçerli bir ifadesi operator*aşırı edildi. (Soru "C" olarak etiketlenmiş olsa da)
dan04

13
@ dan04: Birisi bunu gerçekten yaptıysa ... HAYIR!
Kevin

2
(A) bildirilen ilk hatadan itibaren tavsiye için +1; ve (b) hatanın bildirildiği yerden geriye doğru bakmak. Sen bir olduğunu biliyorum gerçek :-) otomatik bir hata bildirilir nerede önce hat üzerinde baktığınızda programcı
TripeHound

@TripeHound ÖZELLİKLE çok fazla sayıda hata olduğunda veya önceden derlenen satırlar hata atıyorsa ...
Tin Wizard

1
Genellikle meta ile ilgili olduğu gibi, birisi zaten sordu - meta.stackoverflow.com/questions/266663/…
StoryTeller - Unslander Monica

27

Derleyici neden eksik noktalı virgülü algılamıyor?

Hatırlanması gereken üç şey var.

  1. C'deki satır sonları sadece sıradan boşluklardır.
  2. *C'de hem tekli hem de ikili operatör olabilir. Tek terimli bir operatör olarak "referans", ikili operatör olarak "çarpma" anlamına gelir.
  3. Tekli ve ikili operatörler arasındaki fark, görüldükleri bağlamdan belirlenir.

Bu iki gerçeğin sonucu, ayrıştırdığımız zamandır.

 temp = *a    /* Oops, missing a semicolon here... */
 *a = *b;

Birinci ve sonuncu *tekli olarak yorumlanırken ikincisi *ikili olarak yorumlanır. Sözdizimi açısından bakıldığında, bu iyi görünüyor.

Derleyici, işleçleri işlenen türleri bağlamında yorumlamaya çalıştığında, yalnızca ayrıştırmadan sonra bir hata görülür.


4

Yukarıda bazı iyi cevaplar var, ancak detaylandıracağım.

temp = *a *a = *b;

Bu aslında bir durumdur x = y = z;nerede hem xve ydeğerini atanır z.

Ne söylüyorsun the contents of address (a times a) become equal to the contents of b, as does temp.

Kısaca *a *a = <any integer value>geçerli bir ifadedir. Daha önce belirtildiği gibi, birincisi *bir göstericiye referansta bulunurken, ikincisi iki değeri çarpar.


3
Referans önceliği alır, bu nedenle (a adresinin içeriği) kez (a'ya işaretçi) olur. Bunu anlayabilirsiniz, çünkü derleme hatası bu iki tür olan "ikili * 'ye geçersiz işlenenler (' struct S 've' struct S * 'yapısına sahip)" diyor.
dascandy

C99 öncesi kodluyorum, bu yüzden bool yok :-) Ama iyi bir noktaya değindiniz (+1), ancak atama sırası cevabımın asıl amacı olmasa da
Mawg, Monica

1
Ancak bu durumda, ybir değişken bile değildir, bu ifadedir *a *ave bir çarpmanın sonucunu atayamazsınız.
Barmar

@Barmar gerçekten ama derleyici o kadar ileri gitmiyor, atama operatörüne bakmadan önce "ikili *" için işlenenlerin geçersiz olduğuna karar verdi.
2017

3

Çoğu derleyici kaynak dosyalarını sırayla ayrıştırır ve bir şeylerin yanlış olduğunu keşfettikleri satırı bildirir. C programınızın ilk 12 satırı, geçerli (hatasız) bir C programının başlangıcı olabilir. Programınızın ilk 13 satırı olamaz. Bazı derleyiciler, karşılaştıkları, kendi başlarına hata olmayan ve çoğu durumda daha sonra kodda hataları tetiklemeyecek, ancak başka bir şeyle birlikte geçerli olmayabilecek şeylerin konumunu not edeceklerdir. Örneğin:

int foo;
...
float foo;

Beyanname int foo;tek başına gayet iyi olurdu. Beyanname gibi float foo;. Bazı derleyiciler, programcının önceki tanımın aslında hatalı olduğu durumları belirlemesine yardımcı olmak için, ilk bildirimin göründüğü satır numarasını kaydedebilir ve bu satırla bir bilgi mesajı ilişkilendirebilir. Derleyiciler ayrıca a gibi bir şeyle ilişkili satır numaralarını tutabilir do, bu da ilişkili whiledoğru yerde görünmezse raporlanabilir . Sorunun olası konumunun, hatanın keşfedildiği satırın hemen önünde olduğu durumlarda, derleyiciler genellikle konum için fazladan bir rapor eklemeye zahmet etmezler.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.