'int main;' 유효한 C / C ++ 프로그램?


113

내 컴파일러가 그렇게 생각하지 않는 것 같아서 묻습니다.

echo 'int main;' | cc -x c - -Wall
echo 'int main;' | c++ -x c++ - -Wall

Clang은 이에 대해 경고 또는 오류를 발행하지 않으며 gcc는 단순한 경고 만 발행 'main' is usually a function [-Wmain]하지만 C로 컴파일 된 경우에만 발행합니다 . a를 지정하는 -std=것은 중요하지 않은 것 같습니다.

그렇지 않으면 잘 컴파일되고 연결됩니다. 그러나 실행하면 SIGBUS(나를 위해) 즉시 종료됩니다 .

C 및 C ++에서 main ()무엇을 반환해야합니까? 에서 (우수한) 답변을 읽으십시오 . 언어 사양을 빠르게 살펴보면 주 기능 이 필요한 것 같습니다 . 그러나 gcc의 말 ( 'main'은 일반적 으로 함수 임) (그리고 여기서 오류의 부족)은 아마도 그렇지 않다는 것을 암시하는 것 같습니다.-Wmain

그런데 왜? 이것에 대해 이상한 가장자리 사례 또는 "역사적"사용이 있습니까? 누구든지 무엇을 제공하는지 알고 있습니까?

내 요점은 이것이 호스팅 환경에서 오류 라고 생각한다는 것입니다 .


6
gcc를 (대부분) 표준 호환 컴파일러로 만들려면 필요합니다gcc -std=c99 -pedantic ...
pmg

3
@pmg 그 같은 경고, 또는없는 -pedantic-std. 내 시스템 c99도 ... 경고 또는 오류없이 컴파일
제프 닉슨

3
안타깝게도 "충분히 영리하다면"컴파일러에서 받아 들일 수 있지만 말이되지 않는 것을 만들 수 있습니다. 이 경우 C 런타임 라이브러리를 연결하여 main작동하지 않을 라는 변수를 호출합니다 . 당신이 "오른쪽"값으로 주요 초기화 할 경우, 실제로 ... 반환 할 수 있습니다
매트 피터슨

7
그리고 그것이 유효하더라도 끔찍한 일입니다 (읽을 수없는 코드). BTW, 그것은 (모르는하는 호스트 구현과 독립 구현에 다를 수 있습니다 main)
실레 Starynkevitch

1
더 재미 시간의 경우, 시도main=195;
imallett

답변:


97

질문은 C와 C ++로 이중 태그가 지정 되었기 때문에 C ++와 C에 대한 이유는 다릅니다.

  • C ++는 링커가 전역 변수 xyz와 독립형 전역 함수와 같이 서로 다른 유형의 텍스트로 동일한 기호를 구별 할 수 있도록 이름 맹 글링을 사용 합니다 xyz(int). 그러나 이름 main은 결코 엉망이 아닙니다.
  • C는 맹 글링을 사용하지 않기 때문에 프로그램이 다른 심볼 대신 한 종류의 심볼을 제공하여 링커를 혼동하고 프로그램이 성공적으로 연결되도록 할 수 있습니다.

이것이 여기서 일어나는 일입니다. 링커는 symbol을 찾을 것으로 예상 main하고 있습니다. 더 잘 알지 못하기 때문에 해당 기호를 마치 함수 인 것처럼 "연결"합니다. main링커 에게 요청하기 위해 제어를 전달하는 런타임 라이브러리 부분 main이므로 링커는 심볼을 제공 main하여 링크 단계가 완료되도록합니다. 물론 이것은 main함수가 아니기 때문에 런타임에 실패 합니다.

다음은 동일한 문제에 대한 또 다른 그림입니다.

xc 파일 :

#include <stdio.h>
int foo(); // <<== main() expects this
int main(){
    printf("%p\n", (void*)&foo);
    return 0;
}

파일 yc :

int foo; // <<== external definition supplies a symbol of a wrong kind

컴파일 :

gcc x.c y.c

이것은 컴파일되고 아마도 실행될 것이지만 정의되지 않은 동작입니다. 컴파일러에 약속 된 심볼의 유형이 링커에 제공된 실제 심볼과 다르기 때문입니다.

경고가 진행되는 한 합리적이라고 생각합니다. C를 사용하면 main기능 이없는 라이브러리를 빌드 할 수 있으므로 알 수없는 이유로 main변수를 정의해야하는 경우 컴파일러는 다른 용도로 이름 을 해제합니다 main.


3
그러나 C ++ 컴파일러는 주 함수를 다르게 취급합니다. 그 이름은 extern "C"없이도 엉망이되지 않습니다. 그렇지 않으면 연결을 보장하기 위해 자체 extern "C"main을 방출해야하기 때문이라고 생각합니다.
UldisK 2015 년

@UldisK 네, 직접 알아 차렸고 꽤 흥미로 웠습니다. 말이되지만 나는 그것에 대해 생각해 본 적이 없다.
Geoff Nixon

2
사실, C ++와 C에 대한 결과가 없습니다 여기에 지적했듯이, 다른 - main있다 없다 (이 것 때문에) C ++로 엉망으로 이름에 따라이 기능 여부.
Geoff Nixon

4
@nm 질문에 대한 해석이 너무 좁다 고 생각합니다. 게시물 제목에 질문을하는 것 외에도 OP는 자신의 프로그램이 처음에 컴파일 된 이유에 대한 설명을 분명히 찾습니다 ( "내 컴파일러가 그렇게 생각하는 것 같습니다. 비록 내가하지 않더라도 ")뿐만 아니라 main함수가 아닌 다른 것으로 정의 하는 것이 왜 유용 할 수 있는지에 대한 제안 . 대답은 두 부분에 대한 설명을 제공합니다.
dasblinkenlight

1
기호 main이 이름 맹 글링의 대상이 아니라는 것은 부적절합니다. C ++ 표준에는 이름 변경에 대한 언급이 없습니다. 이름 맹 글링은 구현 문제입니다.
David Hammen

30

main하지 않은 것입니다 예약어 그냥의 미리 정의 된 식별자 (같은 cin, endl, npos당신이라는 변수를 선언 할 수 있도록 ...) main, 그 값을 출력 한 후 초기화합니다.

물론이야:

  • 이 경고는 오류가 발생하기 쉬우므로 유용합니다.
  • main()함수 (라이브러리) 없이 소스 파일을 가질 수 있습니다 .

편집하다

일부 참조 :

  • main 예약어가 아닙니다 (C ++ 11) :

    이 기능 main은 프로그램 내에서 사용되지 않습니다. 의 연결 (3.5) main은 구현에 따라 정의됩니다. 삭제 또는 메인 선언으로 주요 정의하는 프로그램이 될 수 있습니다 inline, static또는 constexpr잘못 형성된다. 이름 main은 달리 예약되어 있지 않습니다. [예 : 멤버 함수, 클래스 및 열거 형은 main다른 네임 스페이스의 엔터티처럼 호출 될 수 있습니다 . — 최종 예]

    C ++ 11-[basic.start.main] 3.6.1.3

    [2.11 / 3] [...] 일부 식별자는 C ++ 구현 및 표준 라이브러리 (17.6.4.3.2)에서 사용하도록 예약되어 있으며 다른 방법으로 사용해서는 안됩니다. 진단이 필요하지 않습니다.

    [17.6.4.3.2 / 1] 특정 이름 및 함수 서명 집합은 항상 구현에 예약되어 있습니다.

    • 이중 밑줄 __을 포함하거나 밑줄로 시작하고 그 뒤에 대문자 (2.12)가 오는 각 이름은 모든 용도로 구현에 예약되어 있습니다.
    • 밑줄로 시작하는 각 이름은 전역 네임 스페이스에서 이름으로 사용하기 위해 구현에 예약되어 있습니다.
  • 프로그래밍 언어의 예약어 .

    예약어는 프로그래머가 재정의 할 수 없지만 미리 정의 된 단어는 종종 일부 용량에서 재정의 될 수 있습니다. 다음의 경우입니다 main. 해당 식별자를 사용하는 선언이 의미를 재정의하는 범위가 있습니다.


- 내가 오히려 사실을 속인 것 같아 (그것으로이 되어 있으므로 발생하기 쉬운 오류)이 경고 (안 오류) 왜, 그리고 그것을 C로 컴파일 경고 만하는 이유 - 물론, 당신은없이 컴파일 할 수 있습니다 main()기능,하지만 당신은 프로그램으로 링크 할 수 없습니다. 여기에서 일어나고있는 것은 "유효"프로그램이없이 연결되고 있다는 것입니다 main(), 단지를 main.
제프 닉슨

7
cinendl기본 네임 스페이스에없는 - 그들은에있어 std네임 스페이스. npos의 회원입니다 std::basic_string.
AnotherParker

1
main 되는 글로벌 이름으로 예약. 귀하가 언급 한 기타 사항 main및은 미리 정의되어 있지 않습니다 .
Potatoswatter 2015 년

1
main허용되는 항목 에 대한 제한 사항은 C ++ 14 §3.6.1 및 C11 §5.1.2.2.1을 참조하십시오 . C ++는 "구현은 주 함수를 미리 정의하지 않을 것"이라고 말하고 C는 "구현이이 함수에 대한 프로토 타입을 선언하지 않는다"라고 말합니다.
Potatoswatter 2015 년

@manlio : 당신이 인용하고있는 것을 명확히하십시오. 일반 C에 관해서는 인용이 잘못되었습니다. 그래서 나는 그것이 C ++ 표준 중 하나라고 생각합니다.
dhein

19

int main;유효한 C / C ++ 프로그램은?

C / C ++ 프로그램이 무엇인지 완전히 명확하지 않습니다.

int main;유효한 C 프로그램은?

예. 독립 구현은 이러한 프로그램을 허용 할 수 있습니다.main독립된 환경에서 특별한 의미를 가질 필요는 없습니다.

그것은 하지 호스팅 환경에서 유효합니다.

int main;유효한 C ++ 프로그램은?

같게.

왜 충돌합니까?

이 프로그램은에 의미를 필요가 없습니다 당신의 환경을 제공합니다. 독립 환경에서 프로그램 시작 및 종료, 그리고 그 의미main 는 구현에 따라 정의됩니다.

컴파일러가 경고하는 이유는 무엇입니까?

컴파일러는 준수 프로그램을 거부하지 않는 한 원하는 것에 대해 경고 할 수 있습니다. 반면에 경고는 부적합 프로그램을 진단하는 데 필요한 전부입니다. 이 번역 단위는 유효한 호스팅 프로그램의 일부가 될 수 없기 때문에 진단 메시지가 정당합니다.

gcc독립 환경 입니까 , 아니면 호스팅 환경입니까?

예.

gcc-ffreestanding컴파일 플래그를 문서화합니다 . 추가하면 경고가 사라집니다. 커널이나 펌웨어를 빌드 할 때 사용할 수 있습니다.

g++그러한 플래그를 문서화하지 않습니다. 제공하는 것은이 프로그램에 영향을 미치지 않는 것 같습니다. g ++에서 제공하는 환경이 호스팅된다고 가정하는 것이 안전 할 것입니다. 이 경우 진단의 부재는 버그입니다.


17

기술적으로 허용되지 않으므로 경고입니다. 시작 코드는 "main"의 기호 위치를 사용하고 세 가지 표준 인수 (argc, argv 및 envp)를 사용하여 해당 위치로 이동합니다. 그렇지 않으며 링크 타임에 실제로 함수인지, 심지어 해당 인수가 있는지 확인할 수 없습니다. 이것이 int main (int argc, char ** argv)이 작동하는 이유이기도합니다. 컴파일러는 envp 인수에 대해 알지 못하고 사용되지 않고 호출자 정리입니다.

농담으로 다음과 같이 할 수 있습니다.

int main = 0xCBCBCBCB;

x86 시스템에서 경고 및 유사한 내용을 무시하면 컴파일뿐만 아니라 실제로 작동합니다.

누군가는 이와 유사한 기술을 사용하여 여러 아키텍처에서 직접 실행되는 실행 파일 (일종)을 작성했습니다 ( http://phrack.org/issues/57/17.html#article) . 또한 IOCCC- http: //www.ioccc.org/1984/mullender/mullender.c에서 우승하는 데 사용되었습니다 .


1
"기술적으로 허용되지 않으므로 경고입니다."-C ++에서는 유효하지 않습니다.
건배와 hth. - 알프

3
"세 가지 표준 인수 (argc, argv 및 envp)"-여기서 Posix 표준에 대해 이야기하고있을 수 있습니다.
건배와 hth. - 알프

내 시스템 (Ubuntu 14 / x64)에서 다음 줄은 gcc에서 작동합니다.int main __attribute__ ((section (".text")))= 0xC3C3C3C3;
csharpfolk

@ Cheersandhth.-Alf 처음 두 개는 표준이고 세 번째는 POSIX입니다.
dascandy

9

유효한 프로그램입니까?

아니.

실행 가능한 부분이 없기 때문에 프로그램이 아닙니다.

컴파일하는 것이 유효합니까?

예.

유효한 프로그램과 함께 사용할 수 있습니까?

예.

모든 컴파일 된 코드가 유효하기 위해 실행 가능해야하는 것은 아닙니다. 예는 정적 및 동적 라이브러리입니다.

오브젝트 파일을 효과적으로 작성했습니다. 유효한 실행 파일은 아니지만 다른 프로그램이 main런타임에로드하여 결과 파일 의 개체 에 연결할 수 있습니다.

오류 여야합니까?

전통적으로 C ++는 사용자가 유효하지 않은 것처럼 보이지만 언어 구문에 맞는 작업을 수행 할 수 있도록합니다.

확실히, 이것은 오류로 재 분류 될 수 있지만 그 이유는 무엇입니까? 경고가 제공하지 않는 목적은 무엇입니까?

이 기능이 실제 코드에서 사용될 수 있다는 이론적 인 가능성이있는 한, 함수가 아닌 객체를 호출 main하면 언어에 따라 오류가 발생할 가능성은 거의 없습니다 .


라는 이름의 외부에서 볼 수있는 심볼을 만듭니다 main. 라는 이름 의 외부에서 볼 수있는 함수 가 있어야하는 유효한 프로그램이 어떻게 main링크 될 수 있습니까?
Keith Thompson

@KeithThompson 런타임에로드합니다. 명확히 할 것입니다.
Michael Gazonda

기호 유형 간의 차이를 알 수 없기 때문에 가능합니다. 연결은 잘 작동합니다. 실행 (주의 깊게 만들어진 경우 제외)은 작동하지 않습니다.
Chris Stratton

1
@ChrisStratton : Keith의 주장은 심볼이 곱하기 정의되어 있기 때문에 링크가 실패한다는 것입니다. "유효한 프로그램"이 main함수를 정의하지 않으면 유효한 프로그램이 아니기 때문 입니다.
Ben Voigt 2015 년

@BenVoigt 그러나 그것이 라이브러리에 나타나면 링크가 실패하지 않을 것입니다 (아마도 실패하지 않을 것입니다). 프로그램 링크 타임에 int main;정의가 보이지 않기 때문입니다.

6

실제 언어 표준을 인용하여 이미 주어진 답변에 추가하고 싶습니다.

'int main;' 유효한 C 프로그램?

짧은 대답 (내 의견) : 구현이 "독립 실행 환경"을 사용하는 경우에만 해당됩니다.

C11의 모든 다음 인용문

5. 환경

구현은 C 소스 파일을 번역 하고 두 개의 데이터 처리 시스템 환경에서 C 프로그램 을 실행 합니다.이를 번역 환경과 실행 환경이라고합니다. [...]

5.1.2 실행 환경

두 가지 실행 환경이 정의됩니다 : 독립형 및 호스팅 됨. 두 경우 모두 실행 환경에서 지정된 C 함수를 호출하면 프로그램 시작이 발생합니다.

5.1.2.1 독립 환경

독립 환경 (운영 체제의 이점없이 C 프로그램 실행이 발생할 수 있음)에서는 프로그램 시작시 호출되는 함수의 이름과 유형이 구현에 따라 정의됩니다.

5.1.2.2 호스팅 환경

호스팅 환경을 제공 할 필요는 없지만 다음 사양이있는 경우이를 준수해야합니다.

5.1.2.2.1 프로그램 시작

프로그램 시작시 호출되는 함수의 이름은 main 입니다. [...] 그것은 반환 유형이 int이고 매개 변수없이 [...] 또는 두 개의 매개 변수 [...] 또는 동등하거나 다른 구현 정의 방식으로 정의되어야합니다.

이로부터 다음이 관찰됩니다.

  • C11 프로그램은 독립형 또는 호스팅 된 실행 환경을 가질 수 있으며 유효합니다.
  • 독립형이라면 주된 기능이 필요하지 않습니다.
  • 그렇지 않으면 반환 값이 int 유형이어야합니다 .

독립 실행 환경에서는 5.1.2에 필요한 기능이 없기 때문에 시작을 허용하지 않는 유효한 프로그램이라고 주장합니다. 호스팅 된 실행 환경에서 코드는 main 이라는 객체를 도입합니다. 하지만 반환 값을 제공 할 수 없으므로 프로그램이 그렇지 않은 경우 이전과 같이 주장 할 수도 있지만 이러한 의미에서 유효한 프로그램이 아니라고 주장합니다. (예를 들어 데이터 만 제공하고 싶을 수 있음) 실행을 의미하는 경우에는 그렇게 할 수 없습니다.

'int main;' 유효한 C ++ 프로그램?

짧은 대답 (내 의견) : 구현이 "독립 실행 환경"을 사용하는 경우에만 해당됩니다.

C ++ 14 에서 인용

3.6.1 주요 기능

프로그램은 프로그램의 지정된 시작 인 main이라는 전역 함수를 포함해야합니다. 독립 환경의 프로그램이 주 기능을 정의하는 데 필요한지 여부는 구현에 따라 정의됩니다. [...] 반환 유형은 int 유형이어야하지만 그렇지 않은 경우 유형은 구현에서 정의됩니다. [...] 이름 main은 달리 예약되어 있지 않습니다.

여기서는 C11 표준과 달리 시작 기능이 전혀 언급되지 않았기 때문에 독립 실행 환경에 적용되는 제한이 적고 호스팅 된 실행 환경의 경우 C11과 거의 동일합니다.

다시 말하지만 호스팅 케이스의 경우 코드가 유효한 C ++ 14 프로그램이 아니라고 주장하지만 독립 케이스를위한 것이라고 확신합니다.

내 대답은 실행 환경 만을 고려한 것이므로 번역 환경 에서 발생하는 이름 맹 글링이 미리 일어나기 때문에 dasblinkenlicht의 대답이 작용한다고 생각 합니다. 여기에서 위의 인용문이 그렇게 엄격하게 준수되는지 확신 할 수 없습니다.


4

내 요점은 이것이 호스팅 환경에서 오류라고 생각한다는 것입니다.

오류는 귀하의 것입니다. 다음 main을 반환하는 함수를 지정하지 않았습니다 .int 호스팅 된 환경에서 프로그램을 사용하려고했습니다.

다음과 같은 전역 변수를 정의하는 컴파일 단위가 있다고 가정합니다. main . 프로그램을 구성하는 것이 독립 환경에서의 구현에 달려 있기 때문에 이것은 독립 환경에서 합법적 일 수 있습니다.

mainan을 반환하고 int인수를받지 않는 전역 함수를 정의하는 다른 컴파일 단위가 있다고 가정합니다 . 이것이 바로 호스팅 환경의 프로그램에 필요한 것입니다.

독립 환경에서 첫 번째 컴파일 단위 만 사용하고 호스팅 된 환경에서 두 번째 컴파일 단위 만 사용하면 모든 것이 괜찮습니다. 하나의 프로그램에서 둘 다 사용하면 어떨까요? C ++에서 하나의 정의 규칙을 위반했습니다. 그것은 정의되지 않은 행동입니다. C에서는 단일 기호에 대한 모든 참조가 일관성이 있어야한다는 규칙을 위반했습니다. 그렇지 않은 경우 정의되지 않은 동작입니다. 정의되지 않은 행동은 "탈옥, 자유!"입니다. 구현의 개발자에게 카드. 구현이 정의되지 않은 동작에 대한 응답으로 수행하는 모든 작업은 표준을 준수합니다. 구현시 정의되지 않은 동작을 감지하는 것은 말할 것도없고 경고 할 필요가 없습니다.

이러한 컴파일 단위 중 하나만 사용하지만 잘못된 단위를 사용하면 어떻게됩니까? C에서는 상황이 명확합니다. main호스팅 된 환경에서 두 가지 표준 형식 중 하나로 함수를 정의하지 못하는 것은 정의 되지 않은 동작입니다. 당신이 전혀 정의하지 않았다고 가정하자 main. 컴파일러 / 링커는이 오류에 대해 아무 말도하지 않았습니다. 그들이 불평하는 것은 그들에게 좋은 것입니다. C 프로그램이 오류없이 컴파일되고 링크 된 것은 컴파일러가 아니라 당신의 잘못입니다.

main호스팅 된 환경에서 함수를 정의하지 못하는 것은 정의 되지 않은 동작이 아니라 오류 이기 때문에 C ++에서는 명확 하지 않습니다 (즉, 진단해야 함). 그러나 C ++의 하나의 정의 규칙은 링커가 다소 멍청 할 수 있음을 의미합니다. 링커의 역할은 외부 참조를 확인하는 것이며, 하나의 정의 규칙 덕분에 링커는 해당 기호의 의미를 알 필요가 없습니다. 라는 기호를 제공 main했으며 링커는라는 기호를 볼 것으로 예상 main하므로 링커에 관한 한 모든 것이 좋습니다.


4

지금까지 C의 경우 구현 정의 동작입니다.

ISO / IEC9899에 따르면 :

5.1.2.2.1 프로그램 시작

1 프로그램 시작시 호출되는 함수의 이름은 main입니다. 구현은이 함수에 대한 프로토 타입을 선언하지 않습니다. 반환 유형이 int이고 매개 변수없이 정의되어야합니다.

int main(void) { /* ... */ }

또는 두 개의 매개 변수를 사용합니다 (여기서는 argc 및 argv라고합니다. 이름이 선언 된 함수에 로컬이기 때문에 모든 이름을 사용할 수 있음).

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

또는 동등한 것; 또는 다른 구현 정의 방식으로.


3

아니요, 유효한 프로그램이 아닙니다.

C ++의 경우 이는 최근 결함 보고서 1886 : main ()에 대한 언어 연결에 의해 명시 적으로 잘못 구성되었습니다 .

main ()에 명시적인 언어 연결을 제공하는 데 제한이없는 것처럼 보이지만 아마도 형식이 잘못되었거나 조건부로 지원되어야합니다.

결의안에는 다음과 같은 변경 사항이 포함되었습니다.

전역 범위에서 main 변수를 선언하거나 모든 네임 스페이스에서 C 언어 연결로 main 이름을 선언하는 프로그램은 형식이 잘못되었습니다.

이 문구 는 C ++ 1z 초안 인 최신 C ++ 초안 표준 N4527 에서 찾을 수 있습니다 .

clang과 gcc의 최신 버전은 이제이를 오류로 만듭니다 ( 실시간 참조 ).

error: main cannot be declared as global variable
int main;
^

이 결함보고 이전에는 진단이 필요하지 않은 정의되지 않은 동작이었습니다. 반면에 잘못된 형식의 코드는 진단이 필요하며 컴파일러는이를 경고 또는 오류로 만들 수 있습니다.


업데이트 해주셔서 감사합니다! 이것이 이제 컴파일러 진단으로 선택되는 것을 보니 반갑습니다. 그러나 나는 C ++ 표준에서 변화를 발견했다고 말해야한다. (배경은의 이름 맹 글링에 관한 위의 주석을 참조하십시오 main().) main()명시 적 연결 사양 을 허용하지 않는 이유를 이해 하지만 C ++ 연결 이 있어야 한다는 것을 이해 하지 못합니다 . 물론 표준은 (아이테니엄 ABI와 말) 직접 ABI 연계 / 이름 맹 글링을 처리하는 방법 주소, 그러나 실제로이 탈수 것하지 않습니다 에 . 내가 무엇을 놓치고 있습니까? main()main()_Z4mainv
Geoff Nixon

나는 supercat의 의견이 그것을 다루고 있다고 생각 합니다. 구현이 사용자 정의 main을 호출하기 전에 자체 작업을 수행하는 경우 대신 망가진 이름을 호출하도록 쉽게 선택할 수 있습니다.
Shafik Yaghmour 2015 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.