런타임에 함수를 가져올 수 있도록 C ++ 프로그램을 설계하는 방법은 무엇입니까?


10

오늘 저는 특정 소프트웨어 아키텍처를 실현하기 위해 C ++의 기능에 대해 질문하고 싶습니다.

물론 검색을 사용했지만 직접 연결된 답변을 찾지 못했습니다.

기본적으로, 나의 목표는 사용자가 임의로 구성된 물리적 시스템, 예를 들어 운전 차량의 모델링 및 시뮬레이션을 가능하게하는 프로그램을 구축하는 것입니다. 실제 모델 라이브러리 (클래스 내의 함수)가 있다고 가정합니다. 각 함수는 기본 물리적 설명 (예 : 연소 엔진 모델, 공기 역학적 항력 모델, 휠 모델 등)에 따라 일부 입력을 갖고 일부 출력을 반환 할 수 있습니다.

이제 아이디어는 사용자에게 필요에 따라 기능을 구성 할 수있는 프레임 워크를 제공하는 것입니다. 즉, 물리적 동작을 매핑 할 수 있습니다. 프레임 워크는 다른 기능의 출력과 입력을 연결하는 기능을 제공해야합니다. 따라서 프레임 워크는 컨테이너 클래스를 제공합니다. 하나 또는 여러 개의 모델 객체를 보유 할 수있는 COMPONENT라고합니다 (FUNCTION). 이 컨테이너는 다른 구성 요소 (복합 패턴 참조)와 기능 매개 변수 사이의 연결 (CONNECTOR)을 보유 할 수도 있습니다. 또한 컴포넌트 클래스는 수학 솔버 등과 같은 일반적인 숫자 기능을 제공합니다.

기능 구성은 런타임 중에 수행해야합니다. 첫 번째 경우, 사용자는 컴포지션 구조를 정의하는 XML을 가져와 컴포지션을 설정할 수 있어야합니다. 나중에 GUI 추가를 생각할 수 있습니다.

여기에 대한 이해를 돕기 위해 매우 간단한 예가 있습니다.

<COMPONENT name="Main">
  <COMPONENT name="A">
    <FUNCTION name="A1" path="lib/functionA1" />
  </COMPONENT>
  <COMPONENT name="B">
    <FUNCTION name="B1" path="lib/functionB1" />
    <FUNCTION name="B2" path="lib/functionB2" />
  </COMPONENT>
  <CONNECTIONS>
    <CONNECTOR source="A1" target="B1" />
    <CONNECTOR source="B1" target="B2" />
  </CONNECTIONS>        
</COMPONENT>

내 문제가 훨씬 더 일반적이기 때문에 프레임 워크의 기능을 자세히 살펴볼 필요는 없습니다. 프레임 워크 코드 / 프로그램이 컴파일 될 때 사용자 정의 함수뿐만 아니라 실제 문제점 설명도 알 수 없습니다. 사용자가 (XML을 통해 또는 GUI를 통해 나중에) 함수를 선택할 때, 프레임 워크는 함수를 상호 연결하는 옵션을 사용자에게 제공하기 위해 함수 정보를 읽어야합니다. 즉, 입력 및 출력 매개 변수의 정보를 가져와야합니다.

리플렉션의 원리를 알고 있으며 C ++이이 기능을 제공하지 않는다는 것을 알고 있습니다. 그러나 "런타임 중 개체 작성"이라는 개념이 자주 요구된다고 확신합니다. 목표를 달성하려면 C ++에서 소프트웨어 아키텍처를 어떻게 설정해야합니까? C ++가 올바른 언어입니까? 무엇을 간과합니까?

미리 감사드립니다!

건배, 올리버


C ++에는 함수 포인터와 함수 객체가 있습니다. 모든 함수가 실행 파일로 컴파일됩니까, 아니면 어떤 라이브러리에서 동적 라이브러리에 있습니까?
Caleth

1
문제는 일반적으로 전기 공학 / [EDA (electronic design automation)] ( en.wikipedia.org/wiki/Electronic_design_automation ) 또는 기계 공학 / 컴퓨터 지원 설계 (CAD) 에서 대학 학위를 요구한다는 점에서 너무 광범위합니다 . 비교하면 C / C ++ 동적 라이브러리를 호출하는 것은 매우 쉽습니다 . x86에 대한 C 호출 규칙을 참조하십시오 . CPU 스택 포인터를 통해 스택과 CPU 레지스터 값을 조작해야 할 수도 있습니다.
rwong

1
C ++ 언어에서는 동적으로로드되는 기능이 지원되지 않습니다. 플랫폼에 특정한 것을 살펴 봐야합니다. 예를 들어 Windows의 C ++ 컴파일러는 리플렉션 형식을 지원하는 Windows DLL을 지원해야합니다.
Simon B

C ++에서는 컴파일 타임에 서명 (인수 및 반환 유형)을 알 수없는 함수를 호출하는 것이 실제로 어렵습니다. 그렇게하려면 선택한 플랫폼의 어셈블리 수준에서 함수 호출이 작동하는 방식을 알아야합니다.
Bart van Ingen Schenau

2
이 문제를 해결하는 방법은 eval 명령을 지원하는 모든 언어에 대한 인터프리터를 만드는 C ++ 코드를 컴파일하는 것입니다. 뱅 문제는 C ++를 사용하여 해결되었습니다. : P 왜 그렇게 좋지 않은지 생각해보고 질문을 업데이트하십시오. 실제 요구 사항이 명확 할 때 도움이됩니다.
candied_orange

답변:


13

순수한 표준 C ++에서는 "런타임 함수 가져 오기 허용"이 불가능합니다. 표준에 따르면, C ++ 함수 세트는 프로그램을 구성하는 모든 변환 단위 의 결합에서 고정 되었으므로 빌드 타임 (실제로 링크 타임)에 정적으로 알려져 있습니다.

실제로 C ++ 프로그램은 대부분 운영 체제 이상에서 실행됩니다 (내장 시스템 제외) . 좋은 개요를 보려면 운영 체제 : 쉬운 조각 3 개 를 읽으십시오 .

여러 최신 운영 체제 에서 플러그인을 동적으로로드 할 수 있습니다 . POSIX는 특히 dlopen&를 지정합니다 dlsym. Windows에는 다른 것이 있습니다 LoadLibrary(그리고 열등한 연결 모델; 플러그인이 관련, 제공 또는 사용하는 기능에 명시 적으로 주석을 달아야 함). Linux에서 BTW를 사용하면 실제로 dlopen많은 플러그인 을 사용할 수 있습니다 (내 manydl.c프로그램을 참조하십시오. 충분한 인내심을 가지고 거의 백만 개의 플러그인을로드 할 수 있습니다). 따라서 XML로 플러그인을로드 할 수 있습니다. 다중 구성 요소 / 다중 커넥터 설명은 Qt 신호 및 슬롯을 상기시켜줍니다 ( 전처리 기가 필요합니다moc .

대부분의 C ++ 구현은 name mangling을 사용 합니다. 이로 인해 extern "C"플러그인과 관련된 기능으로 정의 dlsym하고 기본 프로그램에서 액세스하여 플러그인으로 정의하는 것이 좋습니다. C ++ dlopen mini HowTo를 읽으십시오 (적어도 Linux의 경우).

BTW, QtPOCO 는 C ++ 프레임 워크로, 플러그인에 대한 이식 가능한 고급 접근 방식을 제공합니다. 그리고 libffi를 사용하면 런타임에만 서명이 알려진 함수를 호출 할 수 있습니다.

또 다른 가능성은 Lua 또는 Guile 과 같은 일부 인터프리터를 프로그램에 포함시키는 것입니다 (또는 Emacs처럼 자신 만의 인터프리터를 작성하십시오). 이것은 강력한 건축 설계 결정입니다. 자세한 내용은 Lisp In Small PiecesProgramming Language Pragmatics 를 읽으십시오 .

이러한 접근 방식에는 변형 또는 혼합이 있습니다. 일부 JIT 컴파일 라이브러리 (예 : libgccjit 또는 asmjit)를 사용할 수 있습니다 . 당신은 생성 할 수있는 런타임에 (나는 이러한 접근 방식을 사용하는 플러그인을로드 동적, 임시 파일에 일부 C 및 C ++ 코드를 임시 플러그인으로 컴파일하고, GCC MELT을 ).

이러한 모든 접근 방식에서 메모리 관리는 중요한 관심사입니다 ( "전체 프로그램"속성이며 실제로 프로그램의 "봉투"는 "변경"입니다). 가비지 수집 에 대한 문화가 적어도 필요합니다 . 용어에 대해서는 GC 핸드북 을 읽으십시오 . 대부분의 경우 (임의의에서 순환 참조 약한 포인터가 예측할 수없는)의 참조 계수 C ++에 대한 계획 친애하는 스마트 포인터가 충분하지 않을 수 있습니다. 참조 .

동적 소프트웨어 업데이트에 대해서도 읽어보십시오 .

Common Lisp (및 Smalltalk ) 와 같은 일부 프로그래밍 언어 는 런타임 가져 오기 기능에 더 친숙합니다. SBCL 은 Common Lisp의 무료 소프트웨어 구현이며 모든 REPL 상호 작용 에서 머신 코드로 컴파일되며 머신 코드 를 가비지 수집 할 수 있으며 나중에 쉽게 다시 시작할 수있는 전체 코어 이미지 파일을 저장할 수 있습니다.


3

분명히 자신 만의 스타일의 Simulink 또는 LabVIEW 유형 소프트웨어를 롤링하려고하지만, 부정한 XML 구성 요소를 사용하려고합니다.

기본적으로 그래프 지향 데이터 구조를 찾고 있습니다. 실제 모델은 노드 (구성 요소라고 함)와 에지 (이름 지정의 커넥터)로 구성됩니다.

리플렉션을 사용하지 않고이를 수행하는 언어 적용 메커니즘이 없으므로 대신 API를 작성해야하며 재생하려는 구성 요소는 여러 기능을 구현하고 API에 의해 설정된 규칙을 준수해야합니다.

각 구성 요소는 다음과 같은 기능을 수행하기 위해 일련의 기능을 구현해야합니다.

  • 구성 요소 이름 또는 기타 세부 사항 가져 오기
  • 구성 요소가 노출하는 입력 또는 출력 수를 가져옵니다.
  • 출력에 대한 특정 입력에 대한 컴포넌트 조사
  • 입력과 출력을 함께 연결
  • 다른 사람

그리고 그것은 단지 그래프를 설정하기위한 것입니다. 모델이 실제로 실행되는 방식을 구성하려면 추가 기능이 정의되어 있어야합니다. 각 기능에는 특정 이름이 있으며 모든 구성 요소에는 해당 기능이 있어야합니다. 컴포넌트마다 컴포넌트와 동일한 방식으로 해당 API를 통해 컴포넌트에 특정한 모든 것이 도달 가능해야합니다.

프로그램은 이러한 '사용자 정의 함수'를 호출하려고하지 않아야합니다. 대신, 각 컴포넌트에서 범용 '컴퓨팅'함수 또는 이와 같은 함수를 호출해야하며 컴포넌트 자체는 해당 함수를 호출하고 입력을 출력으로 변환합니다. 입력 및 출력 연결은 해당 기능에 대한 추상화이며 프로그램에서만 볼 수 있습니다.

간단히 말해서,이 중 일부는 실제로 C ++에만 해당되지만 특정 문제 영역에 맞게 일종의 런타임 유형 정보를 구현해야합니다. API에 의해 정의 된 각 함수를 사용하면 런타임에 호출 할 함수 이름을 알 수 있으며 각 호출의 데이터 유형을 알 수 있으며 일반적인 이전 동적 라이브러리로드를 사용하여 완료 할 수 있습니다. 여기에는 상당한 양의 상용구가 제공되지만 이는 삶의 일부일뿐입니다.

명심해야 할 하나의 C ++ 특정 측면은 사용자가 자신의 모듈을 제공하는 경우 API를 C API로 만드는 것이 가장 좋으므로 다른 모듈에 대해 다른 컴파일러를 사용할 수 있습니다.

DirectShow는 내가 설명한 모든 것을 수행하는 API이며 살펴볼만한 좋은 예가 될 수 있습니다.


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