태그 보관물: function

function

‘int main;’ 유효한 C / C ++ 프로그램? 발행하지 않으며 gcc는 단순한

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

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

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

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



답변

질문은 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.


답변

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. 해당 식별자를 사용하는 선언이 의미를 재정의하는 범위가 있습니다.


답변

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

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

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

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

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

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

같게.

왜 충돌합니까?

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

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

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

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

예.

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

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


답변

기술적으로 허용되지 않으므로 경고입니다. 시작 코드는 “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에서 우승하는 데 사용되었습니다 .


답변

유효한 프로그램입니까?

아니.

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

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

예.

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

예.

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

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

오류 여야합니까?

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

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

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


답변

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

‘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의 대답이 작용한다고 생각 합니다. 여기에서 위의 인용문이 그렇게 엄격하게 준수되는지 확신 할 수 없습니다.


답변

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

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

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

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

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

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

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