Nice programing

g ++로 컴파일되는 이상한 코드

nicepro 2020. 11. 2. 19:38
반응형

g ++로 컴파일되는 이상한 코드


다음 코드는 g ++ 4.8.1로 성공적으로 컴파일됩니다.

int main()
{
    int(*)();
}

함수에 대한 포인터의 간단한 선언처럼 보입니다.

int(*f)();

clang 3.4 및 vc ++ 2013으로 컴파일되지 않습니다.

컴파일러 버그입니까 아니면 표준의 어두운 곳 중 하나입니까?


g ++ 4.8.1 (업데이트 됨)로 잘 컴파일되는 유사한 이상한 코드 조각 목록 :

  1. int(*)();

  2. int(*);

  3. int(*){};

  4. int(*());

이러한 이상한 코드 조각을 사용한 라이브 예제 .

업데이트 1 : @Ali 가 댓글에 흥미로운 정보를 추가했습니다.

4 가지 경우 모두 clang 3.5 trunk (202594)에 컴파일 오류가 발생하고 gcc 4.9 trunk (20140302)로 잘 컴파일됩니다. 동작은 이해할 수있는 -std=c++98 -pedantic점을 제외하고 와 동일합니다 int(*){};. 확장 이니셜 라이저 목록은 -std=c++11.

업데이트 2 :@CantChooseUsernames가 에서 언급 한 그의 대답 그들은 여전히 컴파일 좋은 심지어 g에 의해 그들을 위해 생성없이 조립 초기화와 ++ (어느 쪽과도 초기화없이) 심지어 어떤 활성화 최적화하지 않고 :

  1. int(*)() = 0;

  2. int(*) = 0;

  3. int(*){} = 0;

  4. int(*()) = 0;

초기화가있는 라이브 예제 .

업데이트 3 :int(*)() = "Hello, world!"; 컴파일도 잘 된다는 사실에 정말 놀랐 습니다 ( int(*p)() = "Hello, world!";물론 컴파일하지는 않습니다).

업데이트 4 : 환상적이지만 int(*){} = Hello, world!;잘 컴파일됩니다. 그리고 다음과 같은 매우 이상한 코드도 있습니다 : int(*){}() = -+*/%&|^~.,:!?$()[]{};( 라이브 예제 ).

업데이트 5@zwol는 에서 언급 한 그의 코멘트

이것과 많은 관련 구문 문제가 gcc 버그 68265 로 추적되고 있습니다.


C ++ 표준에 따름 (섹션 7 선언의 6 페이지)

6 init-declarator-list의 각 init-declarator 는 정확히 하나의 declarator-id를 포함합니다 . 이것은 해당 init-declarator에 의해 선언 된 이름이므로 선언에 의해 선언 된 이름 중 하나입니다.

따라서 이것은 단순히 컴파일러 버그입니다.

내 MS VC ++ 2010으로 컴파일 할 수는 없지만 유효한 코드는 예를 들어 (당신이 보여준 함수 포인터 선언과는 별개로) 보일 수 있습니다.

int(*p){};

테스트에 사용중인 컴파일러가 선언자 ID없이 선언을 허용하는 것 같습니다.

섹션 8.1 유형 이름의 다음 단락도 고려하십시오.

1 형식 변환을 명시 적으로 지정하고 sizeof, alignof, new 또는 typeid 인수로 형식 이름을 지정해야합니다. 이는 유형 ID로 수행 할 수 있으며, 이는 엔티티의 이름을 생략하는 해당 유형의 변수 또는 함수에 대한 구문 선언입니다.


이것이 얼마나 도움이되는지 잘 모르겠지만 다음을 시도했습니다 (clang 3.3, g ++ 4.8.1).

using P = int(*)();
using Q = int*;
P; // warning only
Q; // warning only
int(*)(); // error (but only in clang)
int*;     // error
int(*p)(); // ok
int *q;    // ok

반면에 모든 것이 g ++ 4.8.2 및 4.9.0에서 잘 컴파일됩니다. 불행히도 나는 clang 3.4가 없습니다.

대략적 으로 선언 [iso 섹션 7]은 다음과 같은 부분으로 구성됩니다.

  1. 선택적 접두사 지정자 (예 : static, virtual)
  2. 기본 유형 (예 : const double, vector<int>)
  3. 선언자 (예를 들어 n, *p, a[7], f(int))
  4. 선택적 접미사 함수 지정자 (예 : const , noexcept)
  5. 옵션 초기화 또는 함수 본문 (예를 들어, = {1,2,3}또는{ return 0; }

이제 선언자 대략 이름과 선택적으로 일부 선언자 연산자 [iso 8/4]로 구성됩니다.

접두사 연산자, 예 :

  • * (바늘)
  • *const (상수 포인터)
  • & (lvalue 참조)
  • && (rvalue 참조)
  • auto (후행시 함수 반환 유형)

후위 연산자, 예 :

  • [] (정렬)
  • () (함수)
  • -> (함수 후행 반환 유형)

위의 연산자는 표현식에서의 사용을 반영하도록 설계되었습니다. 후위 연산자 바인드 프리픽스보다 더 단단한, 괄호는 그 순서를 변경하는데 사용될 수있다 : int *f()포인터를 반환하는 함수이다 int반면 int (*f)()함수 포인터 반환int 입니다.

Maybe I am wrong, but I think these operators cannot be in the declaration without the name. So when we write int *q;, then int is the base type, and *q is the declarator consisting of prefix operator * followed by name q. But int *; cannot appear by itself.

On the other hand, when we define using Q = int*;, then declaration Q; is fine by itself because Q is the base type. Of course, because we are not declaring anything, we may get an error or a warning depending on compiler options, but this is a different error.

The above are just my understanding. What the standard (e.g. N3337) says is [iso 8.3/1]:

Each declarator contains exactly one declarator-id; it names the identifier that is declared. An unqualified-id occurring in a declarator-id shall be a simple identifier except for the declaration of some special functions (12.3 [user-defined conversions], 12.4 [destructors], 13.5 [overloaded operators]) and for the declaration of template specializations or partial specializations (14.7).

(notes in square brackets are mine). So I understand int(*)(); should be invalid and I cannot say why it has different behaviour in clang and different versions of g++.


You can use this: http://gcc.godbolt.org/ to view the assembly..

int main()
{
    int(*)() = 0;
    return 0;
}

Generates:

main:
    pushq   %rbp
    movq    %rsp, %rbp
    movl    $0, %eax
    popq    %rbp
    ret

Which is equivalent to: int main() {return 0;} So even with NO optimization, gcc just doesn't generate assembly for it.. Should it give a warning or error? I have no clue but it doesn't care or do anything for the unnamed func pointer.

However:

int main()
{
    int (*p)() = 0;
    return 0;
}

With no optimization will generate:

main:
    pushq   %rbp
    movq    %rsp, %rbp
    movq    $0, -8(%rbp)
    movl    $0, %eax
    popq    %rbp
    ret

which allocates 8 bytes on the stack..

참고URL : https://stackoverflow.com/questions/23015482/strange-code-that-compiles-with-g

반응형