main () içindeki return deyimi ve exit ()


197

İçinde ifadeler kullanmalı mıyım exit()yoksa sadece returnifadeler main()mi kullanmalıyım ? Şahsen ben returnaçıklamaları tercih çünkü kodu okurken başka bir işlevi ve akış kontrolü okumak gibi hissediyorum (bence) pürüzsüz. Ve main()işlevi yeniden düzenlemek istesem bile , sahip olmaktan returndaha iyi bir seçim gibi görünüyor exit().

Does exit()şey special yapmak returndeğil mi?

Yanıtlar:


277

Aslında, olan bir fark, ama zekice. C ++ için daha fazla etkisi vardır, ancak farklılıklar önemlidir.

Ben çağırdığınızda returniçinde main()ve yok ediciler benim yerel olarak kapsamlı nesneler için çağrılır. Ben ararsam exit(), hiçbir yıkıcı benim yerel olarak kapsamlı nesneler için çağrılır! Tekrar okuyun. exit() geri dönmez . Bu, onu bir kez çağırdığımda, "backsies" olmadığı anlamına gelir. Bu işlevde oluşturduğunuz hiçbir nesne yok edilmez. Genellikle bunun bir etkisi yoktur, ancak bazen dosyaları kapatmak gibi olur (elbette tüm verilerinizin diske boşaltılmasını mı istiyorsunuz?).

Arasanız bile staticnesnelerin temizleneceğini unutmayın exit(). Son olarak, eğerabort() hiçbir nesnenin yok edilmeyeceğini . Yani, hiçbir global nesne, statik nesne ve hiçbir yerel nesne yıkıcılarını çağırmaz.

Geri dönüşten çıkmayı tercih ederken dikkatli olun.

http://groups.google.com/group/gnu.gcc.help/msg/8348c50030cfd15a


1
abort (), hata koşulu (sıfır olmayan çıkış kodu) ile çıkar ve hatta bir çekirdek olabilir. Statik yıkıcılar çağırmadan çıkmanız gerekiyorsa _exit kullanın.

7
@Mike: C kitaplığı dosya arabellekleri ile C ++ dosya akışı nesneleri arasında bir fark vardır. exit () - C kütüphanesinin bir parçası olmak - öncekiyle koordine etmek ve yıkamak için tasarlanmıştır, ancak ikincisini atlayabilir: Standart C ++ fstream içeriği bile diske boşaltılmaz (deneyin - yaptım, Linux / GCC) ve açık olarak G / Ç arabellekli kullanıcı tanımlı türlerin de temizlenmesi beklenemez.
Tony Delroy

9
Not: Açıklama: yerel olarak kapsamdaki nesnelerim için hiçbir yıkıcı çağrılmayacak! C ++ 11 için artık geçerli değil: - İş parçacığı saklama süresi olan geçerli iş parçacığı ile ilişkili nesneler yok edilir (yalnızca C ++ 11). Ilplat
14:14

7
Yani thread_localnesnelerin yıkıcıları çağrılır. Diğer yerel nesneler için yıkıcılar hala çağrılmaz. ideone.com/Y6Dh3f
HolyBlackCat

3
BTW ve sadece bilgiçlikçi olmak ve bu cevap hala C: C kullanan okuyucular için kafa karıştırıcı olabileceğinden, exit()dosyaları temiz bir şekilde kapatma sorunu aslında yanlıştır. Örneğin, bir kullanım durumunda: Sadece zaman verileri tersi durumda olan boşaltılan olmayabilir returngelen main()ve bir çağrıda setbuf()veya setvbuf()bir tampon içinde otomatik depolanması ilan ile main()(aşağıda R. yanıtında belirtildiği gibi). Bu sorunun hem C hem de C ++ ile etiketlenmesi gerçekten çok kötü (ve kodlama stili - bu bir stil sorunu değil!).
Greg A. Woods

25

Başka bir farklılık: exit Standart Kitaplık işlevidir, bu nedenle üstbilgileri eklemeniz ve standart kitaplıkla bağlantı kurmanız gerekir. Göstermek için (C ++ 'da), bu geçerli bir programdır:

int main() { return 0; }

ama kullanmak exit için aşağıdakilere ihtiyacınız vardır:

#include <stdlib.h>
int main() { exit(EXIT_SUCCESS); }

Ayrıca bu, ek bir varsayım ekler: exitden çağrı mainsıfır döndürme ile aynı yan etkilere sahiptir. Diğerlerinin de belirttiği gibi, bu ne tür bir yürütülebilir dosya oluşturduğunuza bağlıdır (yani, kimin aradığını main). C-çalışma zamanını kullanan bir uygulamayı kodluyor musunuz? Maya eklentisi mi? Bir Windows hizmeti mi? Şoför? Her vakaya exiteşdeğer olup olmadığını görmek için araştırma yapılması gerekecektir return. IMHO gerçekten demek istediğinizexit zaman kodu daha karmaşık hale getirir. OTOH, gerçekten demek istiyorsan , elbette kullan. return exit


16

Orada tercih en az bir nedendir exitsenin herhangi edin: atexitişleyicileri otomatik depolama süreli verilerine atıfta mainya da kullandıysanız setvbufveya setbufstandardın birine atamak için bir otomatik depolama-süresi tampon akarsu mainsonra dönen, mainüretir tanımsız davranış, ancak çağrıexit geçerlidir.

Bir başka potansiyel kullanım (genellikle oyuncak programları için ayrılmıştır), tekrarlayan çağrıları olan bir programdan çıkmaktır main.


1
@Seb hakkında özel bir şey yok main()- sadece diğerleri gibi bir işlev. Öte yandan, standartta özel bir sözü olduğundan, standart, nasıl tanımlandığı main()ve buna yakın ve sevgili şeyler hakkında oldukça dikkatli olmalıdır . Ancak nihayetinde standart otomatik depolama hakkında özel bir şey yapmak için derleyiciler gerektirmez (ve olmamalıdır ) main(). Lütfen yorumunuzda belirttiğiniz paragrafın altındaki 11. dipnotu okuduğunuza dikkat edin.
Greg A. Woods

1
@ GregA.Woods İlginç. Bazı bilgilendirici metnin aksine bazı normatif metinler var gibi görünüyor. Göre ISO / IEC direktifleri , normatif referans, "vazgeçilmez" olarak kabul edilir nerede-olarak bilgilendirici tamamlayıcı olarak kabul edilir sadece ... Ayrıca, kelimenin kullanılması bir gereklilik geçersiz aktarmaya "olacak"; yukarıda belirtilen belgeye göre (Ek H). Özetle, bilgilendirici metin kesinlikle geçersizdir.
otistik

2
@Seb: Amaç, otomatik depolama davranışıyla ilgili gereklilikleri geçersiz kılmak değildir ve dipnot bunu açıklığa kavuşturmak için açıkça yazılmıştır. Evet, C standardında kesin olmayan, zayıf ifadeler var. Bunu okuyan herkes bunu bilir. Ayrıca komitenin genel olarak böyle sorunları çözmediğini biliyoruz çünkü niyet zaten belli.
R .. GitHub DURDURMAK BUZA YARDIM ETMEK

1
@Seb: Bu haklı olduğunuzu kanıtlayan bir tartışma veya mahkeme davası değil. Amaç gerektiğini fiili C dili (olarak amaçlanan ve uygulandığı şekliyle) ne olduğu net bir anlayış elde etmek ve okuyuculara yararlı olan cevapları o ifade edilebilir. Normatif metin, temelde dipnot tarafından tespit edilen bir şekilde (yanlış bir şekilde ifade etmesi gereken şeyin aksine) yanlıştır. Bundan memnun değilseniz, bir hata raporu gönderin, ancak bir yanıt beklemeyin. WG14 böyle işliyor ...
R .. GitHub

3
@Seb: C dilinin, standardın doğal dil metnini tamamen titizmiş gibi yorumlayarak anlaşılabileceğine inanıyorsunuz. Bu mümkün değil. Spesifikasyon hatalar içerir ve WG14, basit bir dipnot zaten bir hata yaptıklarını bildiğini açıkladığında, ancak okuyucunun bunu anlayabildiğini açıkladığında, zamanları yeniden yazmak için zaman kaybetmez.
R .. GitHub BUZA YARDIMCI DURDUR

5

Ben her zaman kullanıyorum returnçünkü için standart prototip main()bir döndürür diyor int.

Bununla birlikte, standartların bazı versiyonları mainözel muamele verir ve açık bir returnifade yoksa 0 döndürdüğünü varsayar . Aşağıdaki kod verildiğinde:

int foo() {}
int main(int argc, char *argv[]) {}

G ++ yalnızca aşağıdakiler için bir uyarı oluşturur foo()ve eksik dönüşü yok sayar main:

% g++ -Wall -c foo.cc
foo.cc: In function int foo()’:
foo.cc:1: warning: control reaches end of non-void function

C'yi bilmiyorum, ancak C ++ standardı, ana değer döndürmezseniz, 0 döndürdüğünü belirtir.
Jason Baker

Görünüşe göre C99 aynı: faq.cprogramming.com/cgi-bin/…
Jason Baker

2
C99 ve C ++ dönüş ifadesi yoksa 0 döndürür, C90 vermez.
d0k

Bir işlevin bir dönüş değerine sahip olduğu bildirilmesi return, yürütmeyi sonlandırmak için kullanmanız gerektiği anlamına gelmez . Arama exit()ayrıca herhangi bir işlevin yürütülmesini sonlandırmak için geçerli ve bazen gerekli bir yoldur. Aslında ben ve başkaları başka bir yerde tarif ettikleri gibiexit() bile gelen main()bütün süreci çıkmadan temlikler çok daha açık bir niyet, otomatik süreç çıkana kadar depolama ve kod geleceği üstlenmeden sırasında daha kolay bakım için yapar korur. C için kullanırken returnde main()niyet sürecini sona erdirmek için zaman böylece belki kötü bir uygulamadır.
Greg A. Woods

@ GregA.Woods bu sizin fikriniz, ancak bir oyu hak etmiyor! Yukarıda yazdıklarım standartla tamamen tutarlıdır , ancak argümanınız sadece anlambilimdir.
Alnitak

5

Ben ŞİDDETLE otomatik depolama zorunda kalmamak için exit () kullanımı hakkında R. tarafından ikinci açıklama main()programı aslında sona ermeden geri. İçindeki bir return X;ifade, main()bir çağrıyla tam olarak eşdeğer değildir exit(X);, çünkü geri döndüğünde dinamik olarak main()kaybolur main(), ancak bunun exit()yerine bir çağrı yapılırsa kaybolmaz .

Ayrıca, C veya herhangi bir dilde C benzeri bir de returnsize denilen C başlangıç rutin sayarsak yürütme bu devam genellikle teknik olarak doğru iken yürütme çağıran işlevi devam edeceği anlamına okuyucuya ifadesi kuvvetli ipuçları main()işlevi, o değil tam olarak ne sen işlemi sona erdirmek isterken demek.

Sonuçta, programınızı başka herhangi bir fonksiyondan sonlandırmak main()istiyorsanız , aramalısınız exit(). Bunu tutarlı bir şekilde yapmak main(), kodunuzu çok daha okunaklı hale getirir ve ayrıca kodunuzu herkesin yeniden hesaba katmasını kolaylaştırır; main()Başka bir işleve kopyalanan kod, çağrı olması gereken yanlışlıkla yapılan returnifadeler nedeniyle hatalı davranmayacaktırexit() .

Sonuç olarak, tüm bu noktaları bir araya getirmek , en azından C'nin programı sona erdirmek için bir ifade kullanmasının kötü bir alışkanlık olduğudur .returnmain()


Sen bulabilir C standart ait 5.1.2.2.3p1 ... ilginç
otistik

Bu cevap, cevapta bağlamsal olarak belirtildiği gibi C programları için dikkatle ele alınmalıdır. C ++ ile kullanım için, daha önce belirtilen tüm uyarılara karşı dikkatlice tartılmalıdır. C ++ için exit()genel olarak kaçınmayı öneririm , ancak a throwveya abort()alternatifler belirli bir bağlamda çalışmazsa bunu kullanırım . Ama özellikle anadan kaçının exit()ve dönüşü tipik uygulama olarak anada kullanmak.
Eljay

5

Exit () 'return' özel bir şeyi yapar mı?

Yaygın olmayan platformlar için bazı derleyicilerle exit(), argümanını programınızın çıkış değerine çevirebilirken, bir dönüş main(), değeri herhangi bir çeviri olmadan doğrudan ana bilgisayar ortamına geçirebilir.

Standart, bu durumlarda aynı davranışı gerektirir (özellikle, intuyumlu olan bir şeyin döndürülmesinin, bu değerle main()çağırmaya eşdeğer olması gerektiğini söyler exit()). Sorun, farklı işletim sistemlerinin çıkış değerlerini yorumlamak için farklı kuralları olmasıdır. Birçok (MANY!) Sistemde 0, başarı anlamına gelir ve başka bir şey başarısızlık demektir. Ancak, örneğin, VMS, tek değerler başarı anlamına gelir ve hatta başarısızlık anlamına gelir. Eğer 0 main()değerini döndürdüyseniz , VMS kullanıcısı erişim ihlaliyle ilgili kötü bir mesaj görür. Aslında bir erişim ihlali yoktu - bu sadece hata kodu 0 ile ilişkili standart mesajdı.

Sonra ANSI ortaya çıktı ve kutsanmış EXIT_SUCCESSve EXIT_FAILUREgeçebileceğiniz argümanlar olarak exit(). Standart ayrıca söylüyor exit(0)özdeş için davranması gerektiği exit(EXIT_SUCCESS)bu yüzden çoğu uygulamaları tanımlamak, EXIT_SUCCESSiçin 0.

Bu nedenle, standart, 0 değerine sahip bir hata kodunu döndürmek için standart bir yol bırakmadığından, sizi VMS'ye bağlar .

1990'lı yılların başındaki VAX / VMS C derleyicisi bu nedenle dönüş değerini yorumlamadı, main()sadece ana bilgisayar ortamına herhangi bir değer döndürdü. Ancak bunu kullandıysanız exit(), standardın gerektirdiği şeyi yapardı: EXIT_SUCCESS(veya 0) bir başarı koduna ve EXIT_FAILUREgenel bir hata koduna çevirin (veya ) . Kullanım için EXIT_SUCCESS, sen vardı onu geçmek exit(), içinden geri olamazdı main(). Derleyicinin daha modern sürümlerinin bu davranışı koruyup korumadığını bilmiyorum.

Taşınabilir C programı şu şekilde görünüyordu:

#include <stdio.h>
#include <stdlib.h>

int main() {
  printf("Hello, World!\n");
  exit(EXIT_SUCCESS);  /* to get good return value to OS */
  /*NOTREACHED*/ /* to silence lint warning */
  return 0;  /* to silence compiler warning */
}

Bir kenara: Doğru hatırlıyorsam, çıkış değerleri için VMS kuralı tek / çiftten daha inceliklidir. Aslında bir önem seviyesini kodlamak için düşük üç bit gibi bir şey kullanır. Bununla birlikte, genel olarak konuşmak gerekirse, garip şiddet seviyeleri başarı ya da çeşitli bilgileri, hatta çiftler hataları gösterdi.


Bazı eski öncesi ANSI derleyiciler değerini tedavi olabileceğini returnedtarafından mainiletilen değerin farklı exit- ancak standart özellikle dönüş tipi ise" diyor mainişleviyle uyumlu bir türüdür int, başlangıç çağrısından bir dönüş mainfonksiyonu olduğunu msgstr "işlevi argüman olarak işlev exittarafından döndürülen değerle çağırmaya eşdeğerdir main". Bu C11; C89 / C90 neredeyse aynı ifadelere sahipti.
Keith Thompson

Aslında. Bununla birlikte, bazı ANSI dönemi derleyicileri bu hakkı elde edemedi ve ana bilgisayar ortamına döndürülen doğru dönüş değerini almak için çıkışın açıkça kullanılmasını gerektirdi. Standart (o zaman bile) 0 ile aynı şekilde işlem görmeyi gerektirdiğinden, 0 değerine sahip EXIT_SUCCESSplatforma özgü bir arıza durumunu döndürmenin bir yolu yoktu , bu yüzden dönemin bazı derleyicilerinin ana dönüşü ve exit()farklı şekilde.
Adrian McCarthy

Bunun için bir alıntı var mı? Ayrı bir konu herhangi olup olmadığıdır güncel derleyiciler bu özel hata var. Cevabınız şimdiki zamanda ifade edilmiştir.
Keith Thompson

Bu adil bir eleştiri. Kapsamı bildiğim özel durumla sınırlamak için ifadeyi değiştirdim.
Adrian McCarthy

0

C yönünden dönüş , aynı değerle mainçağrı yapmakla exittamamen aynıdır.

C standardının 5.1.2.2.3 Bölümü :

Ana işlevin dönüş türü int ile uyumlu bir türse, ilk çağrıdan ana işleve dönüş, ana işlev tarafından argüman olarak döndürülen değerle çıkış işlevini çağırmaya eşdeğerdir ; 11) ana işlevi sonlandıran} değere ulaşmak 0 değerini döndürür. Dönüş türü int ile uyumlu değilse, ana makine ortamına döndürülen sonlandırma durumu belirtilmez.

C ++ için kurallar diğer cevaplarda belirtildiği gibi biraz farklıdır.


-1

Aslında , fonksiyonunuz birden çok kez çağrıldığında exit(0)ve return(0)içinde bir fark vardır .mainmain

Aşağıdaki program

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char** argv) {
  if (argc == 0)
    return(0);
  printf("%d", main(argc - 1, argv));
}

Olarak çalıştırmak

./program 0 0 0 0

Aşağıdaki çıktı ile sonuçlanacaktır:

00000

Ancak bu:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char** argv) {
  if (argc == 0)
    exit(0);
  printf("%d", main(argc - 1, argv));
}

Bağımsız değişkenlerden bağımsız olarak hiçbir şey yazdırmaz.

Hiç kimsenin mainaçıkça sizi aramayacağından eminseniz, teknik olarak büyük bir fark değildir, ancak daha net bir kod sağlamak daha exitiyi görünecektir. Herhangi bir nedenle aramak istiyorsanız main- ihtiyaçlarınıza göre ayarlamanız gerekir.

C. hakkında konuşmak

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.