C ++ 'da main () içinde hiçbir şey bildirmemek ve yine de derlemeden sonra çalışan bir uygulamaya sahip olmak nasıl mümkün olabilir?


86

Bir röportajda şöyle bir soruyla karşılaştım:

Arkadaşınız size Fibonacci numaralarını konsola yazdıran tek bir kaynak kod dosyası verdi. Main () bloğun boş olduğuna ve içinde herhangi bir ifade bulunmadığına dikkat edin.

Bunun nasıl mümkün olduğunu açıklayın (ipucu: küresel örnek!)

Bunu gerçekten bilmek istiyorum, böyle bir şeyin nasıl mümkün olabileceğini!


26
İpucuna bak!
R. Martinho Fernandes

14
Çünkü bu, 1) duymadığım bir şey, 2) faydalı bir trivia çünkü insanlar röportajlarda soruyor, 3) bilmek için ilginç bir dil uygulaması, 4) Onu tanıyabiliyorum ve herkesi suratına bıçaklayabiliyorum üretim kodunda gerçekten kullandıklarını görürsem paslı bir bıçak.
OmnipotentEntity

4
Yetkin, profesyonel bir C ++ programcısı bu sorunun cevabını bilir. Bu mülakat sorusunun amacı, mülakat yapılan kişinin yetkin, profesyonel bir C ++ programcısı olup olmadığını belirlemekse, o zaman soru onlara cevabı vermemelidir.
John Dibling

1
Bir görüşme ortamında, bir alternatif kodunda herhangi işlev içinde mantığı kullanarak çıktıyı log olacaktır assertya #pragma messagebu derleme sırasında konsola çıkış yönlendirir vb. Program hiçbir zaman tam olarak derlenemez, ancak bu kesinlikle görüşme sırasında "kullanıma hazır" düşüncenizi göstermenin eğlenceli bir yoludur. Bu, üretilen ikiliden bahsetmediği için aktarılan soruyu tatmin eder; daha ziyade konsolda "şeyler" gösterebilen bir C dosyasından bahsediyor. ;-)
TheCodeArtist

1
IOCC için bir röportaj mıydı ? :-) Tamam, bunu fabrikalarımı başlatmak veya bazı test kodları yürütmek için sık sık yaptığımı kabul ediyorum. Btw, ' tek kaynak kodu dosyası' da bir ipucudur, giriş noktası (varsayılan olarak ana) bağlayıcı ile değiştirilmez.
Valentin Heinitz

Yanıtlar:


127

Büyük olasılıkla şu şekilde (veya bunun bir çeşidi) uygulanır:

 void print_fibs() 
 {
       //implementation
 }

 int ignore = (print_fibs(), 0);

 int main() {}

Bu kodda, global değişkenin işleve ignoregirmeden önce başlatılması gerekir main(). Şimdi global olanı başlatmak için print_fibs(), her şeyi yapabileceğiniz yerde yürütülmesi gerekiyor - bu durumda fibonacci sayılarını hesaplayın ve yazdırın! Aşağıdaki soruda gösterdiğim benzer bir şey (uzun süre önce sormuştum):

Bu tür kodların güvenli olmadığını ve genel olarak kaçınılması gerektiğini unutmayın. Örneğin, std::coutnesne print_fibs()çalıştırıldığında başlatılamayabilir , öyleyse o zaman std::coutişlevde ne olur ? Bununla birlikte, başka durumlarda, bu tür bir başlatma sırasına bağlı değilse, o zaman başlatma işlevlerini çağırmak güvenlidir (C ve C ++ 'da yaygın bir uygulamadır).


3
@Nawaz Muhtemelen kesin garantileri belirtmeye değer. Bir çeviri birimindeki nesnelerin sırayla başlatılması garanti edilir. Standart akış nesnelerinin, bir std::ios_base::Initnesnenin ilk başlatılmasından önce veya sırasında başlatılması garanti edilir . Ve ad alanı kapsamında <iostream>bir std::ios_base_Initnesnenin bir örneğini içeriyormuş gibi davranması garanti edilir .
James Kanze

3
Steve314 @: Bu bütün ifadenin tipi sağlamak için, ben kullanılan virgül operatörünü ettik yüzden bir şey döndürmez (print_fibs(), 0)olduğunu int. İşte Çevrimiçi Demo .
Nawaz

1
@Nawaz void işlevine ve virgül operatörüne bir alternatif bool, a ve değişken döndürmektir bool fibsPrinted. İşlev yalnızca burada hizmet ediyorsa , bu muhtemelen biraz daha temizdir . (Ama fark muhtemelen endişelenmek için yeterli değil.)
James Kanze

1
+1, harika hakkında konuşun. Sadece bu soruya ve bu cevaba olumlu oy vermek için stackoverflow'a katılmak zorunda kaldım.
Sabit Nokta

1
@Nawaz Ne demek istediğinden emin değilim. Tanımı std::coutkütüphanede bir yerdedir. Zaten belirttiğimiz gibi Ancak, standart gerektiren bir ilk yapıcısı önce sisteme yüklenmek std::ios_base::Initnesne bittikten ve o dahil gerektirir <iostream>bir sanki davranmak std::ios_base::Initnesne ad kapsamda tanımlanan bulundu. Çeviri birimi, <iostream>başlatılmakta olan nesnenin tanımından önce içeriyorsa , std::coutinşa edilmesi garanti edilir.
James Kanze

18

Bu yardımcı olur umarım

class cls
{
  public:
    cls()
    {
      // Your code for fibonacci series
    }
} objCls;

int main()
{
}

Dolayısıyla, sınıfın global bir değişkeni bildirilir bildirilmez, kurucu çağrılır ve orada Fibonacci serisini yazdırmak için mantık eklersiniz.


9

Evet mümkün. Nesne yapıcısında Fibonacci sayılarını hesaplayan bir nesnenin global bir örneğini bildirmeniz gerekir.


6
Başlatıcı Fibonacci sayılarını hesaplayan bir nesnenin global bir örneğini bildirmeniz gerekir.
James Kanze

4

Senin söylediğin gibi bazı örnekler biliyorum. Bunu elde etmenin bir yolu, şablon meta programlamasını kullanmaktır. Bunu kullanarak bazı hesaplama işlemlerini derlemeye taşıyabilirsiniz.

Burada Fibonacci sayıları ile bir örnek alabilirsiniz

Statik bir sınıf yapıcısında kullanırsanız ve ana işlevde herhangi bir kod yazmaya gerek kalmadan sayıları yazabilirsiniz.

Umarım size yardımcı olur.


3

Global / statik değişkenlerin başlatılması sırasında bazı şeyler olabilir. Kod, uygulama başlangıcında tetiklenecektir.


3

Dosya kapsamı nesnelerinin tüm [*] yapıcıları main, nesne dışı dosya kapsamı değişkenleri için tüm başlatıcı ifadeleri gibi erişilmeden önce çağrılır .

Düzenleme: Ayrıca, tüm dosya kapsamı nesneleri için tüm [*] yıkıcılar, mainçıkışlardan sonra ters inşa sırasına göre çağrılır . Teorik olarak, fibonacci programınızı bir nesnenin yıkıcısına koyabilirsiniz.

[*] "Tümü" seçeneğinin, programınızın doğrudan bağlantılı olmadığı kitaplıkları dinamik olarak yükleme ve boşaltma davranışını göz ardı ettiğini unutmayın. Bunlar teknik olarak temel C ++ dilinin dışındadır.


Hepsi mi? Daha sonra açıkça yüklenen dll'lerdekiler bile main?
James Kanze

C ++ teknik olarak dinamik olarak yüklenen kitaplıkları tanımlamaz, bu nedenle saf C ++ içinde ifadem doğrudur. Bu nedenle, "Tümü, main'e ulaştıktan sonra yüklenen DLL'lerde / DSO'larda bulunan başlatıcılar ve dosya kapsamı nesneleri için kaydedin." Bu durumda, mainboştur, bu nedenle bu DLL'lerin / DSO'ların yıkıcılar tarafından yüklenmesi gerekir ki bu çok sapıktır. Ama bu bilgisayar bilimi olduğundan, "hepsi" gibi kelimelere dikkat etmemiz gerektiğini düşünüyorum.
Joe Z

Yukarıdaki cevabıma 'hepsi' üzerine bir uyarı ekledim ve ayrıca dansçılar hakkında bir not ekledim.
Joe Z

Evet, ama umarım o gelir. Ön C ++ 11, DLL'lere izin vermeyi amaçlayan bazı çakal ifadeler içeriyordu, ancak bu, uygulamada yalnızca teknik olarak garantinin, tüm gerçek uygulamalarda olmasına ve çok fazla koda bağlı olmasına rağmen, garantinin her zaman orada olmadığı anlamına geliyordu. C ++ 11 en azından bunu düzeltti.
James Kanze
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.