2016-08-21 4 views
0

수학 라이브러리를 개발 중이며 사용자의 컴퓨터가 SSE (및 어떤 버전)를 지원하는지 여부를 감지하여이를 기반으로 별도의 내부 함수를 동일한 API 함수를 호출 할 수 있습니다. 나는 그것을 구현하는 세 가지 방법을 생각할 수 있습니다C99 : 정적 라이브러리의 동적 디스패치

  1. 라이브러리에서 글로벌 함수 포인터를하고 자신의 소스에서 사용자 호출 mathInit()를 할 수 있습니다. 그들이 할 때, 하드웨어 세부 사항을 파악하고 다른 기능에 함수 포인터를 할당하십시오.

  2. 동일하지만 전역 함수 포인터 대신에 구조체을 넣고 mathInit()에서 반환합니다. 이렇게하면 사용자는 math.vec3Add (...) 또는 이와 유사한 메서드를 호출해야합니다. 1과 동일하지만, 대신 글로벌 포인터를 갖는

  3. , mathInit을()는 때문에 함수 포인터는 사용자의 main() 함수에서 지역의 범위가 (그리고 mathInit이 필요하다고() 메인에서 호출 할 매크로()). 물론 헤더에있을 것입니다.

이러한 방법 중 어느 것이 좋습니까? 다른 방법이 있습니까?

+0

3은 여기에 ifs 또는 buts가 없습니다. –

+0

@ n.m. 전에는 함수 포인터로 작업하지 않았으므로이 세 가지 모두가 꽤 우아하지 않게 보였다. 그러므로 질문입니다. –

답변

1

이것은 주로 의견을 바탕으로 한 IMHO입니다.

내 생각에, 수학 라이브러리는 내부 작업에 대한 최소한의 세부 정보를 노출해야하며 가능하면 사용자 코드와 관련하여 까다로운 함수 포인터 또는 데이터 구조 또는 매크로가 필요하지 않아야합니다.

나는 (1)로 가서 라이브러리의 함수 포인터를 완전히 숨길 것이라고 가정합니다. 즉, 라이브러리 코드의 간접 참조를 통해 호출합니다. 직접적 분명하지 않은 사용자 코드에 제한을두고 있기 때문에

(3), 확실히 최악의 방법입니다. 또한 사용자 코드를 디버깅 할 때 명백하지 않은 문제/관찰을 생성 할 수 있습니다.

(2) 매우 드문 방법으로 라이브러리를 제공하고 적어도 중간 수준의 C 유창성이 필요하며 전문적인 C 사용자가 아닌 사용자를 제외시킬 수 있습니다.

는 또한 SSE 및 비 SSE 기능과 함께 hasSSE 기능을 노출하고 사용자 코드에 사용하는 어떤 결정을 떠날 수 있습니다. 그러나 그것이 (1)에 대한 어떠한 이점도 가지고 있는지는 확실하지 않습니다.

+0

C 라이브러리의 틀에 얽매이지 않는 인터페이스를 제외하고 (2)의 다른 문제가 있습니까? 미래에 이것을 사용하여 핫로드 가능한 공유 라이브러리를 작성하기로 결정할 것이므로 전역을 피하는 것이 좋습니다. –

+0

공유 라이브러리의 변수에 기술적 인 문제가 보이지 않습니다. 어쨌든 응용 프로그램에 * 글로벌 * 일 필요는 없습니다. 라이브러리에서 간접적으로 '정적'으로 쉽게 만들 수 있습니다. 그리고 "자유로운 인터페이스"- 특히 수학 기능은 비 전문 프로그래머가 자주 사용한다는 것을 기억하십시오. 나는 그것을 어떤 댓가 로라도 피할 것이다. – tofro

+0

라이브러리는 주로 내 엔진 용으로 내부적으로 사용됩니다. 공유 라이브러리의 전역에 관해서 : http://nullprogram.com/blog/2014/12/23/ [세번째 단락] –

0

내 제안은 각 명령어 세트 (예 : Xnosse.o Xsse3.o Xsse4.o 등)에 대해 별도의 단위를 컴파일하고이를 위해 자동 디스패처를 사용합니다. 사용자는 자신의 PC에서 최상의 성능을 얻고 내부 세부 사항을 신경 쓰지 않아도됩니다.

코드를 라이브러리에 작성 했으므로 라이브러리로드시 호출 될 init 함수를 사용하여 자동으로로드 시간에 대한 디스패치를 ​​결정할 수 있습니다. 이 결정은 함수가 실제로 호출 된 첫 번째 시간에만 실행되도록 만들 수 있습니다. 이것은 지연 바인딩을위한 것입니다.

다음은 코드 예입니다 (gcc에만 해당!)

컴파일 단위 : 라이브러리에 이제

//Xnosse.c 
void do_some_math_stuff_no_sse(int x, int y) 
{ 
    ...do some sophisticated math stuff with no sse support 
} 
void do_some_other_math_stuff_no_sse(int x, int y) 
{ 
    ...do some other sophisticated math stuff with no sse support 
} 

//Xsse3.c 
void do_some_math_stuff_sse3(int x, int y) 
{ 
    ...do some sophisticated math stuff with sse3 support 
} 
void do_some_other_math_stuff_sse3(int x, int y) 
{ 
    ...do some other sophisticated math stuff with sse3 support 
} 

//Xsse4.c 
void do_some_math_stuff_sse4(int x, int y) 
{ 
    ...do some sophisticated math stuff with sse4 support 
} 
void do_some_other_math_stuff_sse4(int x, int y) 
{ 
    ...do some other sophisticated math stuff with sse4 support 
} 

:

//my_math.h 
/* Following definitions are in my_math.c */ 
extern void (*do_some_math_stuff)(int x, int, y); 
extern void (*do_some_other_math_stuff)(int x, int y); 

//my_math.c 
void not_set(int x, int y) 
{ 
    // If you don't want to use the constructor for any reason, 
    // say you want lazy binding, this will do the trick as our 
    // functions do_math_stuff and do_other_math_stuff are initialized 
    // to this one 
    setup(); 
} 

void (*do_some_math_stuff)(int x, int, y) = not_set; 
void (*do_some_other_math_stuff)(int x, int y) = not_set; 

int detect_sse() 
{ 
    ..Do runtime detection of sse version 
} 

/* The following function will be called when your library loads */ 
void __attribute__ ((constructor)) setup(void) 
{ 
    if (detect_sse() == 0) 
    { 
     do_some_math_stuff = do_some_math_stuff_no_sse; 
     do_some_other_math_stuff = do_some_other_math_stuff_no_sse; 
    } 
else if (detect_sse() == 3) 
    { 
     do_some_math_stuff = do_some_math_stuff_sse3; 
     do_some_other_math_stuff = do_some_other_math_stuff_sse3; 
    } 
else if (detect_sse() == 4) 
    { 
     do_some_math_stuff = do_some_math_stuff_sse4; 
     do_some_other_math_stuff = do_some_other_math_stuff_sse4; 
    } 
} 

당신이 게으른 바인딩하려면 설정에서 생성자 decorater를 제거하고 컴파일 :

gcc -Wall -shared -fPIC -o libmy_math.so my_math.c Xnosse.c Xsse3.c Xsse4.c 

하는 경우 라이브러리에서로드 할 때 다음과 같은 추가 매개 변수를 사용하면 동적 디스패처가 실행되기를 원합니다. g cc :

gcc -Wall -shared -Wl,-init,setup -fPIC -o libmy_math.so my_math.c Xnosse.c Xsse3.c Xsse4.c 
+0

이것은 기본적으로 전역 변수를 사용하므로 사용자가 mathInit()을 호출 할 필요가 없습니다. ; 맞지? mathInit에 문제가 없다. 엔진에 전체 초기화 서브 시스템이있다. 내 질문은 전역 함수 포인터를 사용하는 것이 올바른지 여부이다. –

+0

전역 함수 포인터를 사용하는 것이 좋다.이 함수 포인터를 호출하는 함수 사용하기 어쨌든 당신이 신경 써야 할 유일한 것은 사용자에게 드러내는 것입니다 - 그 최선의 접근법은 기능입니다 –

관련 문제