2013-06-07 2 views
1
합격 클래스

인해 정의되지 않은 vtable에 C에서 레이아웃 ++, 하지만 명시 적으로 호출 규칙을 설정하고 가상 함수 및 상속을 피하면 무슨 나쁜 생각입니까? 즉DLL 경계를 넘어서 vtable없이 C++ 구조체를 전달합니까? DLL 경계를 넘어

, 내가 안전하게 DLL에서 다음과 같은 구조체에 대한 포인터를 전달할 수 있을까?

struct MyStruct { 

    int a; 
    int b; 

    WINAPI MyStruct(int a, int b) 
     : a(a), b(b) 
    {} 

    void WINAPI SetA(int a) { 

     this->a = a; 
    } 
}; 

등등 differetnt 컴파일러 버전과 같은 DLL에 링크를 사용하는 것이 안전 할 것인가?

+0

vtables 및 상속과 함께 모든 관련 코드가 동일한 컴파일러 및 옵션으로 컴파일 된 경우 어떤 문제가 발생할 수 있는지 알 수 없습니다. – PlasmaHH

+1

함수가 인라인 인 경우 오브젝트 레이아웃이 동일해야합니다 올바른 포장/정렬 (예 : # pragma 팩과 함께) 그러면 SetA 함수가 dll을 '호스팅'하는 앱으로 컴파일됩니다. 다른 옵션은 vtbl의 함수 포인터를 수동으로 생성하는 것입니다. – Pete

답변

2

코드는 다음과 같은 C 코드에 정말 동일합니다 : 가상 함수를 방지

struct MyStruct { 
    int a; 
    int b; 
}; 

void WINAPI InitMyStruct(struct MyStruct* p, int a, int b) 
{ 
    p->a = a; p->b = b; 
} 

void WINAPI MyStruct_SetA(struct MyStruct* p, int a) 
{ 
    p->a = a; 
} 

기본적으로 당신에게 아무것도 구입하지 않았다; 이 "동등한"C 함수가 호출되는 ("이름 맹 글링") 것은 컴파일러에 따라 다르므로 호환되는 컴파일러를 사용해야합니다. 이 천년기의 MSVC의 모든 버전은이 점에서 서로 호환됩니다. 이 천년기의 모든 GCC 버전은 서로 호환됩니다. 두 개를 섞지 마십시오 (링크 타임 오류가 발생합니다).

이 포장/정렬 설정이 일치해야합니다 (그러나 그들은뿐만 아니라, 일반 C 인터페이스에 대해 그렇게 필요) :

문제의 다른 소스가 있습니다. 당신이 동일한 컴파일러 버전을 사용하고 DLL 런타임 라이브러리를 사용하지 않는

하나 DLL에서 "새"를 사용하고 다른에서 "삭제"하는 경우

, 당신은 문제가 될 수 있습니다. 따라서 클라이언트 코드에서 new 또는 delete MyStruct 개체를 사용하지 마십시오. DLL 대신 DLL을 통해 기능을 제공하십시오. 멀리 인터페이스의 표준 라이브러리 컨테이너에서

그대로. DLL과 클라이언트가 동일한 표준 라이브러리에 연결되어 있지 않으면 작동하지 않습니다.

는 가상 함수의 두려워하지 마십시오.

: 이러한 모든 문제뿐만 아니라 다른 플랫폼에서 이론적으로 존재하지만,

1

은 어느 쪽 DLL 경계도 vtable을 어떤 특별한 없습니다 리눅스 및 Mac OS X 용 연습에 약간의 관련성이 적은 것으로 나타납니다 방법. 방출 단위 경계는 다음과 같습니다.

하나의 실행 파일에 다른 컴파일러, 다른 컴파일러 버전 또는 때로는 다른 컴파일러 옵션으로 컴파일 된 객체를 혼합하면 프로그램의 다른 부분에서 호환되지 않는 객체 레이아웃을 얻을 수 있습니다. 이것은 DLL이나 정적 연결을 사용하고 모든 종류의 개체, vtable 또는 그렇지 않은 경우에 발생할 수 있습니다. 실행 파일과 DLL을 모두 컴파일하고 전체적으로 함께 출시되는

그래서, 당신은 걱정할 필요가 없다. 실행 파일과 DLL이 독립된 조직에서 별도로 릴리스 한 다른 제품인 경우 매우주의해야합니다. 릴리스 단위 경계에서 C 호환 데이터 구조 만 사용하고 다른 단위로 할당 된 메모리는 절대로 사용하지 않는 것이 좋습니다.

관련 문제