C ++ 'da işlev bildiriminden sonra noktalı virgül ('; ') gerekmez mi?


174

Kısa bir süre önce bir ara programlama testi yaptım ve yanlış yaptığım sorulardan biri şuydu:

Bir işlev bildiriminden sonra noktalı virgül (';') gerekmez.

Doğru ya da yanlış.

Ben "yanlış" seçti (ve eğer yanlış olduğumu lütfen beni düzeltin çünkü deli gibi hissediyorum), bir fonksiyon bildirimi (kodun üstünde) tanımından önce yazdığınız şey yani derleyici işlevi biliyor hatta çağırmadan önce çağırın ve işlevi bir bütün olarak oluşturan işlev tanımıdır .

yani,

Beyan:

int func();

Tanım:

int func() {
  return 1;
}

Bunun cevabı yanlış olmamalı mı?


41
Bir tanım da bir deklarasyondur. Ama cevabınızın doğru olduğunu söyleyebilirim.

216
Bu zor bir nitpicking sorusu ve kimsenin iyi programlama yeteneği üzerinde hiçbir etkisi yoktur.
phonetagger

40
Her zaman çift olumsuzluklarla sonuçlanan, kafa karıştırıcı soruları buluyorum. Aklımda, bu tür sorular öğrencileri yukarı çıkarmak için tasarlanmıştır. Soru neden şu şekilde oluşturulamadı: "Bir noktalı virgül (';') her zaman bir işlev bildiriminden sonra ihtiyaç duyulur. Doğru veya Yanlış."? : /
Algirdas Preidžius

18
@phonetagger Tüm bu karışıklık sorunun ne kadar kötü ifade edildiğini gösteriyor.
François Andrieux

34
Hanlon'dan Razor , testin yazarının "beyan" ve "tanım" ı birbirine karıştırdığını ileri sürüyor.
Sneftel

Yanıtlar:


161

Fonksiyonu tek bir adımda bildirip tanımladığınız bir duruma sahip olabilirsiniz, yani işlev tanımını bildirdiğiniz noktaya eklerseniz. Yani teknik olarak doğru olduğunu düşünüyorum. Ama soru öyle ki, sizin yaptığınız gibi cevaplayacağım.


10
Verdiğin nedenden ötürü doğrunun doğru olmadığını iddia ediyorum. Noktalı virgül gerektiğinde durumlar yanlışsa (veya doğru değil). Doğru benim için mutlaktır, eğer ihtiyaç duyulduğunda net durumlar varsa, doğru diyemezsiniz.
Funball

16
@IFunball İyi argüman. Aptal doğal diller. Bir işlev bildirimi sonrasında "noktalı virgül (';') cümlesine" işlev bildirimi sonrasında "noktalı virgül (';' ) gerekli değildir (hiç) veya" A noktalı virgül ('; " msgstr " ) , işlev bildiriminden sonra (her zaman) gerekli değildir ". İfadeyi doğru ya da yanlış olarak nitelendirmek, bir yorumu seçmeye dayanır. Kesin olarak konuşulan soru belirsizdir ve bu nedenle net bir cevabı yoktur.
Peter - Monica'yı eski

6
@IFunball Bunun nedeni, daha fazla bağlamı ve dil avukatlığı yaptığımız ifadesi olmayan "beyan" ın "tanımlayıcı olmayan bir beyan" anlamına geldiği anlaşılmaktadır. Soru haksızdı.
Yörüngedeki Hafiflik Yarışları

2
Test edilmekte olan içeriği bilen biri için belirsiz olan herhangi bir sınav sorusu hatalıdır.
Nat

2
İngilizce diline tanımlanmamış bir davranış maddesi eklememiz gerekiyor gibi görünüyor
Nick Mertin

147

"Bir tanım aynı zamanda bir bildirimdir" şeye ek olarak, aşağıdaki yasal C ++:

int f(), g();

Bu, iki işlev bildirir fve ghem argüman olmadan hem de dönüş türü ile int, ancak tanımını fnoktalı virgülle (hemen) izlemez. Aynı şekilde bu yasaldır:

int f(), i = 42;

Ancak, gerçekten bu durumlarda noktalı virgülün tamamen atlanmasına izin verilmez, bu nedenle, aşağıdaki noktalı virgül olmadan bir bildirime örnek olarak alınması biraz şaşırtıcı olacaktır. Aslında, aşağıdakiler yasa dışıdır:

void *p, f() {}

(Sadece) bir işlev bildirimi dışında, bir işlev tanımı aynı tür belirticiye yönelik herhangi bir bildirim veya tanımla birleştirilemez . (Bu yasal olsaydı, a hem tanımlayacak void *pve void f() {}.)

Her durumda, bu bir ara programlama testinde olmaması gereken bir "gotcha" sorusu gibi görünüyor.

(Oh, bu arada, lütfen aslında kod yazmayın int f(), i = 42;.)


2
Bir işlev türünü tanımlamak için bir typedef kullanmak ve daha sonra bunu aynı anda birçok işlevi bildirmek için kullanmak da mümkündür, örneğin typedef int fooProc(int); fooProc a,b.c.d.e;disket sürücüsü tabanlı derleyiciler için standart başlıkların bunu neden geri yapmadığından emin değilim. çünkü başlık dosyalarının çok daha küçük ve dolayısıyla daha hızlı işlenmesine izin vereceğini düşünürdüm.
supercat

Ayrıca int f(int(&g)(),int(*h)()){return g()+h();}, bunun bir açık kıvırcık ayraç, bir diğeri virgül ve üçüncüsü yakın parantez ile izlenen üç işlev bildirimi olduğunu düşünün .
David Hammen

1
@DavidHammen: Bu kesinlikle başka işlevler beyan etmiyor int f(stuff). Hatta işlev kapsamında, gtipi otomatik bir değişkendir fonksiyon referans ve ha, işlevi için işaretçi .
Peter Cordes

83

Diğer cevaplar ve yorumlar bunun korkunç, yanıltıcı ve kötü yazılmış bir soru olduğunu söyler. Ancak henüz kimsenin tanımlayamadığı bir sorun daha var. Soru:

Bir işlev bildiriminden sonra noktalı virgül (';') gerekmez. Doğru ya da yanlış.

Tamam, bir işlev bildirimine bakalım:

int func();       /* */
/*           ^       */
/*           |       */
/* That whitespace is "after the function declaration". */

Bütün bunlar deklarasyon . Beyan edilmez int func()ve daha sonra takip bir ;. Beyannamenin int func();ardından boşluk bırakılır.

Öyleyse soru şu: Bildirgeden sonra noktalı virgül gerekli mi? Tabii ki değil. Deklarasyonda zaten sona eren bir noktalı virgül var. Deklarasyondan sonra noktalı virgül anlamsız olacaktır. Aksine, bir işlev bildiriminden sonraint func(); ; noktalı virgül olur .

Soru neredeyse kesin olduğu amaçlanan soru sormak için "doğru veya yanlış: bir işlev bildiriminde son belirteç daima bir noktalı" Ama sınav yazarı sorun hakkında açıkça düşünmüyordum çünkü, yazdıkları soru değil.

Benim tavsiyem, dil sınavlarını tamamen programlamaktan kaçınmaktır. Çok korkunçlar.


Biz konudayken eğlenceli bir gerçek. C # 'da bunların tümü yasaldır:

class C {}
class D {};
struct E {}
struct F {};

C # 'da, sınıf veya yapı bildirimi, noktalı virgülle bitebilir veya bitmeyebilir. Bu garip küçük özellik, parmak uçlarında tip bildirimlerinin anlamsız bir noktalı virgülle sona erdiği C # 'a gelen C / C ++ programcılarının yararı için eklendi; tasarım ekibi bu alışkanlığa sahip oldukları için onları cezalandırmak istemedi. :-)


Yorumlar uzun tartışmalar için değildir; bu görüşme sohbete taşındı .
Samuel Liew

25

Bunun gibi bir işlev de bildirebilirsiniz:

int func(){
    return 1;
}

Açıklama çok belirsiz. Doğru cevap şu olmalıdır: işlevi nasıl beyan ettiğinize bağlıdır.

Her neyse, ben de yanlış seçerdim ve belki soruyu birine bildirebilirsin.


3
Her neyse, şeyi kişisel bir seviyeye koyma. Önemli olan, bir işlev beyanı tanımının nasıl çalıştığını anlamanızdır, bu yüzden çok fazla endişelenmeyin, sadece sorunun en azından kontrol edileceğinden ve devam edeceğinden emin olun
Luca Corsini

11
Kesinlikle. Dürüst olmak gerekirse, soru bildirimi tanımı hakkında soruyu yanlış anlayarak, doğru şekilde anladığımdan daha fazla şey öğrendim.
Logan

1
@Logan fazla endişelenme. Tek ihtiyacınız olan bir fonksiyonun nasıl yazılacağını ve okunacağını biliyorsanız. Kişisel olarak 1. iyi tanımlanmayan bu tür sorulardan nefret ediyorum 2. sözdizimi hakkındaki teorik bilginizi test edin. Benim için kas hafızası gibi. Her rakamı yazdığım zaman zahmetsizce anahtara gider, ama bana hangi tuşların bir rakam basması gerektiğine dair bir test verirseniz, eylemi fiziksel olarak yapmak için bir klavye olmadan tamamen umutsuz
olurdum

2
... Ortak sözdizimi yazmak (örneğin bir işlev gibi) sizin için ikinci bir nitelik olacaktır. Ve dilleri karıştırdığınızda, dilleri değiştirdiğiniz için, iyi ... zekice ve sözdizimi vurgulama hızlı ve verimli çözümler üretir. Daha faydalı bir şeye zaman ve enerjinizi yatırın.
bolov

20

Bir işlev bildiriminden sonra noktalı virgül (';') gerekmez.

Doğru ya da yanlış.

Doğru . Herhangi bir bildirimden sonra noktalı virgül gerekmez. Ne de herhangi bir tanımdan sonra. Ne de herhangi bir açıklamadan sonra.

Bölüm 7'deki [dcl.dcl] sözdiziminin belirttiği gibi, birçok bildirim türünün noktalı virgülle bitmesi gerekir. Ancak bundan sonra ikinci bir tane yazmaya gerek yoktur.


1
Eric Lippert'in bu noktayı zaten tartıştığını görüyorum. Sanırım tüm upvotes beni göz ardı etti. Oyunuzu orada kullanmaktan çekinmeyin.
Marc van Leeuwen

"X her zaman doğrudur: doğru mu yanlış mı?" "yanlış" cevabına sahip olacak. Heck, hiçbir yerde noktalı virgül kullanmaya gerek yok ; derleyici, programınızı derlemeyi şikayet edebilir ve reddedebilir, ancak bu dünyanın sonu gelmez; Ben buna temel ihtiyaç demezdim . ;)
Quuxplusone

@Quuxplusone derleyici programınızı reddederse, programınızda herhangi bir işlev bildirimi yoktur :)
Ben Millwood

6

Bu, işlevi bildirmemize veya tanımlamamıza bağlıdır. İşlevi bildirirsek, noktalı virgül ( ;) eklememiz gerekir ve işlevi tanımlarsak noktalı virgül gerekmez.

Bir deklarasyon şöyle:

int add(int, int);

Ve bir tanım şöyle:

int add(int a, int b)
{
    // ...
}

10
Bu cevapla ilgili sorun, tanımların ve bildirimin birbirini dışladığını öne sürmesidir. Aslında, her tanım bir bildirgedir; tanımlar bir alt kümedir.
MSalters

6

Hemen hemen tüm diğer cevapları kabul etsem de, sorunun çok belirsiz olduğunu ve cevabınızın teknik olarak doğru olduğunu belirterek, farklı bir bakış açısı sunmama izin verin:

Onları hep böyle aradım:

void func();  // The function prototype

...

void func()
{
    // The function definition
}

Sorunun bu terminolojiyi göz önünde bulundurarak oluşturulduğunu varsayıyorum.

Tanım ve deklarasyon benim gözümde aynı kavram. "X = y'yi tanımlarım" == "x = y'yi beyan ederim".

Ancak elbette, fonksiyon prototipi (üstte) ve fonksiyonun gerçek tanımı arasında büyük bir fark vardır.


Benim için prototipiniz nasıl öğrendiğime (ya da yanlış olduğunuzu söylememe) dayanan bir beyandır, ancak bir prototipin argümanların sayısını ve türünü veya geçersizliğini belirtmesini beklerim, ancak bunu atlamanızı umuyorum kısalık için.
David S

David S: Evet, tabii ki aynı zamanda argümanların sayısını ve türünü de içerecekti, ama aslında onları kısalık için atladım (gerçek işlev bildiriminde de argüman olmadığını unutmayın). Ancak, tam işlev bildiriminin prototip olarak adlandırıldığını söylediğinizde gerçekten aynı fikirde değilim. Vikipedi: "bir işlev prototipi veya işlev arabirimi, işlevin adını ve tür imzasını belirten bir işlev bildirimidir (arity, parametrelerin veri türleri ve dönüş türü), ancak işlev gövdesini atlar."
Opifex

@DavidS: C ++ 'da, işlev bildirimleri her zaman prototip (veya tanım) ve void func();tam olarak eşdeğerdir void func(void);. Bu çok farklıdır C , void func();args hakkında derleyici şey söylemez ve aynı şey değildir void func(void);. Bir sonraki prototip veya tanım aksi arayan varsayılan arg promosyonları uygulamak zorundadır iyi bir fikir vardır (örneğin şamandıra -> çift ve dar tamsayı türleri için int. Variadic fonksiyonlara args için aynı kurallar.)
Peter Cordes

Özür dilerim, burada C ile ilgili bir şeye baktım ve dil değişikliğini not etmedim. Yorumumu netlik açısından silmeyeceğim, ancak geri çekildiğini düşünün.
David S

6

Aldığınız sorunun "hemen sonra" dememesi üzücü. Örneğin şunu yazabiliriz:

int func()  /* My function */ ;

Veya şunu yazabilirim:

int func()
int a = 42;

İlk durumda noktalı virgül, bildirimin hemen ardından değildir , ancak sorun olmaz.

İkinci durumda, açıklamadan "sonra", ancak hemen sonra değil noktalı virgül vardır.

Eric Lippert de doğru karar verdi galiba onun cevabını .

"İngilizce bir cümlenin bitiminden sonra bir süre olmalı mı?" Tartışmalı olarak, bir cümlenin sonunda bir dönemi vardır (aksi takdirde cümle olmaz) ve bu yüzden cümlenin ardından bir süre olmamalıdır .


4
Güzel. Bu cümleyi fazladan bir süre ile bitirmek. Orada ne yaptığınızı görüyorum.
David S

2
int func() int a=42;derlemez. Virgül lazım, başkasına değil int. Bkz. Bu cevaptaki tek yeni şey, İngilizce cümlelere benzeyen son paragraftır.
Peter Cordes

1
İkinci örneği derledim demedim. Beyan "belirsiz" bir noktalı virgül gerektiğini söyledi. Benim örnek ilanından sonra noktalı virgül vardı ama değil derlemek.
Nick Gammon

1
Aynı sorun hata iletilerinde de oluşur; C # 'dan sık kullanılan bir örnek " Parametre parametresi, resmi parametre listesindeki son parametre olmalıdır " dır . Şimdi, diyelim ki "Bir frob, bir gloob listesindeki son gloob olmalı" dedim. Bu (1) Her gloob listesinin sonunda bir frob olduğu gibi, her sorunun sonunda bir soru işareti olduğu gibi, (2) Gloob listesinin herhangi bir sayıda frob olabilir, ancak bir veya daha fazla frob varsa , son öğe bir frob olmalı, çift sayının herhangi bir sayıda 02468 olabileceği gibi, ancak bir tanesi son olmalı veya ...
Eric Lippert

... (3) bir gloob listesinde sıfır veya bir frob olabilir ve eğer varsa, sonunda gelir mi? Eğer bağlamı bilmiyorsanız, (1) en mantıklı açıklama olduğunu düşünürdüm, ama "params parametresi" durumunda, (3) doğru açıklamadır. Programlama dili elemanlarının gayri resmi açıklamaları, teknik editör arkadaşlarımın "COIK" olarak adlandırdığı bir özelliğe sahiptir - Yalnızca Biliniyorsa Temizle. Malzemeyi zaten tam olarak anlamadıysanız, bir açıklaması sizin için işe yaramaz, ancak zaten iyice anladıysanız, açıklamaya ihtiyacınız yoktur!
Eric Lippert

4

Yalnızca ;prototipler için kullanabilirsiniz .


4

Bu biraz zor bir soru, ama böyle bir şey anlamına gelen beyan kelimesini kullandılar :

int example();

Bu durumda bu doğrudur.

Eğer uygulama kelimesini kullanırlarsa yanlış olur.


2

Noktalı virgül (;) derleyiciye bu noktalı virgül (;) sonrasında yeni bir deyimin başladığını söylemek için kullanılır.

Bu yüzden noktalı virgül (;) yalnızca bir işlev bildirimi sırasında gerekli olduğunu düşünüyorum. Bana göre, cevap doğru olacak.


Ancak beyanlar ifade değildir.
HolyBlackCat

ancak işlev bildiriminden sonra, derleyici kullanarak yeni bir kod satırı yürütüyoruz. böylece kod derleyici yeni bir satır yürütmeden önce nerede kod önceki satırının sadece bittikten sonra bir derleyici yerel kod (yani 0101) üretebilir bilmek zorunda olduğunu düşünüyorum.
Jatinder

2

Main () öğesinden önce işlevler tanımlandığında :

  • Noktalı virgül gerekmez, çünkü işlev zaten tanımlanmıştır

Main () öğesinden sonra işlevler tanımlandığında :

  • Noktalı virgül gerekir, çünkü bu işlevi prototiplendiriyorsunuz ve derleyiciye işlevin çıktığını söylüyorsunuz.
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.