함수 포인터 정의가 앰퍼샌드 '&'또는 별표 '*'와 함께 작동하는 이유는 무엇입니까?


216

다음은 왜 작동합니까?

void foo() {
    cout << "Foo to you too!\n";
};

int main() {
    void (*p1_foo)() = foo;
    void (*p2_foo)() = *foo;
    void (*p3_foo)() = &foo;
    void (*p4_foo)() = *&foo;
    void (*p5_foo)() = &*foo;
    void (*p6_foo)() = **foo;
    void (*p7_foo)() = **********************foo;

    (*p1_foo)();
    (*p2_foo)();
    (*p3_foo)();
    (*p4_foo)();
    (*p5_foo)();
    (*p6_foo)();
    (*p7_foo)();
}

답변:


224

여기에는 이러한 연산자의 모든 조합이 동일한 방식으로 작동 할 수 있도록 몇 가지가 있습니다.

이러한 모든 작업이 수행되는 근본적인 이유는 (와 같은 foo) 함수가 함수 에 대한 포인터로 암시 적으로 변환 가능하기 때문입니다. 이것이 void (*p1_foo)() = foo;작동하는 이유 foo입니다. 암시 적으로 자체에 대한 포인터로 변환되고 해당 포인터가에 할당됩니다 p1_foo.

단항 &은 함수에 적용될 때 객체에 적용될 때 객체의 주소를 생성하는 것처럼 함수에 대한 포인터를 생성합니다. 일반 함수에 대한 포인터의 경우 암시적인 함수에서 함수로의 포인터 변환으로 인해 항상 중복됩니다. 어쨌든 이것이 void (*p3_foo)() = &foo;작동하는 이유 입니다.

단항 *은 함수 포인터에 적용될 때 객체에 대한 일반 포인터에 적용될 때 지정된 객체를 생성하는 것처럼 뾰족한 함수를 생성합니다.

이 규칙들을 결합 할 수 있습니다. 두 번째에서 마지막 예를 고려하십시오 **foo.

  • 먼저 foo암시 적으로 자체에 대한 포인터로 변환되고 첫 번째 *는 해당 함수 포인터에 적용되어 함수를 foo다시 생성 합니다.
  • 그런 다음 결과는 다시 암시 적으로 자신에 대한 포인터로 변환되고 두 번째 *는 적용되어 다시 함수를 생성합니다 foo.
  • 그런 다음 암시 적으로 함수 포인터로 다시 변환되어 변수에 할당됩니다.

을 원하는만큼 추가 할 수 *있으며 결과는 항상 같습니다. *s가 많을수록 메리 어.

우리는 또한 다섯 번째 예를 고려할 수 있습니다 &*foo.

  • 첫째, foo암시 적으로 자신에 대한 포인터로 변환됩니다. 단항 *이 적용되어 foo다시 산출 됩니다.
  • 그런 다음에 &가 적용 foo되어에 대한 포인터가 생성 foo되고 이에 변수가 할당됩니다.

&전용은 아니지만 (함수 포인터로 변환 된 함수에 대한 함수에 적용 할 수 물론 함수 포인터 결과가 가리키는 포인터 A-포인터 타입 인 경우의 변수이며, 않으면 기능을 수행합니다 (예 : 목록에 추가 할 수 있음 void (**pp_foo)() = &p7_foo;).

이것이 &&foo작동하지 않는 이유입니다 &foo. 함수가 아닙니다. rvalue 인 함수 포인터입니다. 그러나 &*&*&*&*&*&*foo마찬가지로, 일하는 것이 &******&foo있기 때문에 그 표현의 모두에서 &항상 함수에 아닌를 rvalue의 함수 포인터에 적용됩니다.

*함수 포인터를 통해 호출 할 때 단항식 을 사용할 필요는 없습니다 . 모두 (*p1_foo)();(p1_foo)();다시 때문에 함수에 대한 함수 포인터 변환에, 동일한 결과를 갖는다.


2
@Jimmy : 함수 포인터에 대한 참조가 아니라 함수 포인터 일뿐입니다. &foo의 주소를 가져 와서 foo함수 포인터가을 가리 키도록합니다 foo.
Dennis Zickefoose

2
&객체에 대한 연산자를 연결할 수 없습니다 . given int p;, &p포인터를 생성하고 prvalue 표현식입니다. &연산자는 좌변 식을 필요로한다.
James McNellis

12
동의하지 않습니다. 더 *의는 덜 메리 .
세스 카네기

28
예제 구문을 편집하지 마십시오. 언어의 기능을 보여주기 위해 예제를 매우 구체적으로 선택했습니다.
James McNellis

7
부수적으로, C 표준은 &*서로 취소 (6.5.3.2) 의 조합이 "The unary & operator yields the address of its operand."/-/ 이라고 명시 적으로 명시하고 "If the operand is the result of a unary * operator, neither that operator nor the & operator is evaluated and the result is as if both were omitted, except that the constraints on the operators still apply and the result is not an lvalue."있습니다.
룬딘

9

C는 기본 시스템에 대한 추상화 일 뿐이며 추상화가 유출되는 곳 중 하나라는 것을 기억하는 것이 도움이된다고 생각합니다.

컴퓨터의 관점에서 볼 때 기능은 메모리 주소 일 뿐이며 실행되면 다른 명령을 수행합니다. 따라서 C의 함수 자체는 주소로 모델링되므로 함수가 가리키는 주소와 "동일한"디자인으로 이어질 수 있습니다.


0

&*심볼에 멱등 작업 C의 함수로서 선언하는 수단 func == *func == &func == *&func이므로*func == **func

이 유형을 의미 int ()와 동일 int (*)()기능의 파라미터로서 전달 될 수있는 정의 FUNC로서 *func, func또는 &func. (&func)()와 동일합니다 func(). Godbolt 링크.

함수는 따라서 정말 주소 *&의미가 없으며, 대신 오류를 생산, 컴파일러 선택한다면이 FUNC의 주소로 해석 할 수 있습니다.

&기호 함수 포인터를 선언하지만 (지금 별도의 목적을 가지고 있기 때문에) 포인터의 주소를 얻을 것이다 반면 funcp*funcp동일 할 것이다

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.