C ++에서 main () 내부에 아무것도 선언하지 않고 컴파일 후 작동하는 응용 프로그램을 갖는 방법은 무엇입니까?


86

인터뷰에서 나는 다음과 같은 질문에 직면했습니다.

친구가 콘솔에 피보나치 수를 인쇄하는 단일 소스 코드 파일을 제공했습니다. main () 블록은 비어 있고 내부에 명령문이 없습니다.

이것이 어떻게 가능한지 설명하십시오 (힌트 : 글로벌 인스턴스!)

나는 이것에 대해 정말로 알고 싶습니다. 어떻게 그런 일이 가능할 수 있는지!


26
힌트를보세요!
R. Martinho Fernandes

14
왜냐하면 1) 내가 들어 보지 못했던 것, 2) 사람들이 인터뷰에서 물어보기 때문에 유용한 퀴즈, 3) 알아 두어야 할 언어의 흥미로운 적용 4) 나는 그것을 알아볼 수 있고 얼굴에있는 사람을 찌를 수있다 프로덕션 코드에서 실제로 사용하는 것을 보면 녹슨 칼입니다.
OmnipotentEntity 2013

4
유능하고 전문적인 C ++ 프로그래머라면이 질문에 대한 답을 알 것입니다. 이 인터뷰 질문 의 목적이 인터뷰 대상자가 유능하고 전문적인 C ++ 프로그래머인지 확인하는 것이라면 질문으로 답을주지 않아야합니다.
John Dibling

1
인터뷰 설정에서 한 가지 대안은 코드의 함수 내에 논리를 포함하고 assert또는 #pragma message등을 사용하여 출력을 기록하는 것입니다. 이렇게하면 컴파일 중에 출력이 콘솔로 리디렉션됩니다. 프로그램이 완전히 컴파일되지 않을 수도 있지만, 이것은 인터뷰 중에 "즉석"사고를 보여주는 재미있는 방법입니다. 이것은 생성되는 바이너리에 대해 아무것도 언급하지 않기 때문에 인용 된 질문을 만족시킵니다. 오히려 콘솔에 "stuff"를 표시 할 수있는 C 파일에 대해 이야기합니다. ;-)
TheCodeArtist jul.

1
IOCC 인터뷰 였나요 ? :-) 좋아, 나는 공장을 초기화하거나 테스트 코드를 실행하기 위해 자주 수행한다는 것을 인정한다. Btw, ' 단일 소스 코드 파일'은 또한 entry-pint (기본적으로 main)가 링커로 대체되지 않는다는 힌트입니다.
Valentin Heinitz

답변:


127

다음과 같이 구현 될 가능성이 높습니다.

 void print_fibs() 
 {
       //implementation
 }

 int ignore = (print_fibs(), 0);

 int main() {}

이 코드에서 전역 변수 ignoremain()함수에 들어가기 전에 초기화되어야 합니다. 이제 전역을 초기화하려면 print_fibs()무엇이든 할 수있는 곳에서 실행해야합니다.이 경우에는 피보나치 수를 계산하고 인쇄합니다! 나는 다음 질문에서 비슷한 것을 보여주었습니다.

이러한 코드는 안전하지 않으며 일반적으로 피하는 것이 가장 좋습니다. 예를 들어 std::cout객체 print_fibs()가 실행될 때 초기화되지 않을 수 있습니다. 그렇다면 std::cout함수에서 무엇을할까요? 그러나 다른 상황에서 이러한 초기화 순서에 의존하지 않는 경우 초기화 함수를 호출하는 것이 안전합니다 (C 및 C ++에서 일반적으로 사용됨).


3
@Nawaz 아마도 정확한 보증을 인용 할 가치가 있습니다. 번역 단위 내의 개체는 순서대로 초기화됩니다. 표준 스트림 개체는 개체의 첫 번째 초기화 이전이나 도중에 초기화 std::ios_base::Init됩니다. 그리고 네임 스페이스 범위 <iostream>에있는 std::ios_base_Init개체 의 인스턴스가 포함 된 것처럼 "마치"동작하도록 보장됩니다 .
James Kanze 2013

3
@ Steve314 : 쉼표 연산자를 사용하여 전체 표현식의 유형 (print_fibs(), 0)int. 여기에 온라인 데모가 있습니다.
Nawaz 2013

1
@Nawaz void 함수 및 쉼표 연산자에 대한 대안은 a bool및 변수 를 반환하는 것 bool fibsPrinted입니다. 함수가 여기에서만 제공 된다면 아마도 약간 더 깨끗할 것입니다. (그러나 차이는 걱정을 충분히 아마하지 않습니다.)
제임스 간제

1
+1, 멋진 이야기. 이 질문 과이 답변을 찬성하기 위해 stackoverflow에 가입해야했습니다.
Fixed Point '

1
@Nawaz 나는 당신의 요점이 무엇인지 잘 모르겠습니다. 의 정의 std::cout는 라이브러리 어딘가에 있습니다. 그러나 내가 이미 지적했듯이 표준 std::ios_base::Init 객체 의 첫 번째 생성자 가 완료 되기 전에 초기화되어야하며 , <iostream>include는 std::ios_base::Init객체가 네임 스페이스 범위에서 정의 된 것처럼 동작 해야합니다 . 번역 단위 <iostream>가 초기화되는 객체의 정의 이전에 포함 std::cout되는 경우 구성이 보장됩니다.
James Kanze 2013

18

도움이 되었기를 바랍니다

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

int main()
{
}

따라서 클래스의 전역 변수가 선언 되 자마자 생성자가 호출되고 여기에 피보나치 시리즈를 출력하는 논리를 추가합니다.


9

네 가능합니다. 객체 생성자에서 피보나치 수를 계산하는 객체의 전역 인스턴스를 선언해야합니다.


6
이니셜 라이저가 피보나치 수를 계산하는 객체의 전역 인스턴스를 선언해야합니다.
James Kanze 2013

4

나는 당신이 말하는 것과 같은 몇 가지 예를 알고 있습니다. 그것을 얻는 한 가지 방법은 템플릿 메타 프로그래밍을 사용하는 것입니다. 이를 사용하여 일부 컴퓨팅 프로세스를 컴파일로 이동할 수 있습니다.

여기 에서 피보나치 수에 대한 예를 얻을 수 있습니다.

정적 클래스 생성자에서 사용하고 주 함수에 코드를 작성할 필요없이 숫자를 작성할 수 있습니다.

도움이 되었기를 바랍니다.


3

전역 / 정적 변수를 초기화하는 동안 상황이 발생할 수 있습니다. 코드는 응용 프로그램 시작시 트리거됩니다.


3

파일 범위 객체에 대한 모든 [*] 생성자는 객체가 main아닌 파일 범위 변수에 대한 모든 이니셜 라이저 표현식과 마찬가지로 에 도달하기 전에 호출 됩니다.

편집 : 또한 모든 파일 범위 개체에 대한 all [*] 소멸자는 main종료 후 생성의 역순으로 호출 됩니다. 이론적으로 피보나치 프로그램을 객체의 소멸자에 넣을 수 있습니다.

[*] 'all'은 프로그램이 직접 연결되지 않은 라이브러리를 동적으로로드 및 언로드하는 동작을 무시합니다. 기술적으로는 기본 C ++ 언어 밖에 있습니다.


모두 ? 이후에 명시 적으로로드 된 dll의 경우에도 main?
James Kanze 2013

음, C ++는 기술적으로 동적으로로드 된 라이브러리를 정의하지 않으므로 순수 C ++ 내에서 내 진술이 정확합니다. 따라서 "All, main에 도달 한 후로드 된 DLL / DSO에 포함 된 이니셜 라이저 및 파일 범위 개체에 대해 저장합니다." 이 경우, main은 비어 있으므로 해당 DLL / DSO는 소멸자에 의해로드되어야하며 이는 비뚤어진 것입니다. 그러나 이것은 컴퓨터 과학이기 때문에 "all"과 같은 단어에주의해야한다고 생각합니다.
Joe Z '

위의 답변에 '모두'에 대한 경고를 추가하고 dtor에 대한 메모도 추가했습니다.
Joe Z

예,하지만 그럴 것입니다. Pre C ++ 11에는 DLL을 허용하기위한 일부 족제비 문구가 포함되어 있었지만 실제로는 기술적으로 만 의미가 있었지만 모든 실제 구현에 있었지만 많은 코드가 그것에 의존 했음에도 불구하고 보장이 항상 존재하지는 않았습니다. C ++ 11은 적어도 수정했습니다.
James Kanze 2013
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.