programing

C에서의 반사 지원

oldcodes 2023. 8. 22. 22:27
반응형

C에서의 반사 지원

지원이 안 되는 건 알지만, 혹시 주변에 묘책이 있는지 궁금합니다.팁 있어요?

일반적으로 반사는 프로그램이 일부 코드의 구조를 분석하는 수단입니다.이 분석은 코드의 효과적인 동작을 변경하는 데 사용됩니다.

분석으로서의 반사는 일반적으로 매우 약합니다. 일반적으로 함수와 필드 이름에 대한 액세스만 제공할 수 있습니다.이 취약성은 기본적으로 언어 구현자가 소스 코드에서 원하는 것을 추출하기 위한 적절한 분석 루틴과 함께 런타임에 전체 소스 코드를 사용할 수 없도록 하려는 경우에 발생합니다.

또 다른 접근법은 컴파일러가 하는 방식으로 소스 텍스트를 정확하게 구문 분석할 수 있는 강력한 프로그램 분석 도구를 사용하여 프로그램 분석을 직접 해결하는 것입니다.그러나 그것은 보통 작동하지 않습니다. 컴파일러 기계는 컴파일러가 되기를 원하며 다른 목적으로 그것을 구부리는 것은 어렵습니다.)

필요한 것은 다음과 같은 도구입니다.

  • 언어 원본 텍스트를 구문 분석
  • 프로그램의 모든 세부 정보를 나타내는 추상 구문 트리를 만듭니다.(AST가 주석 및 열 번호, 리터럴 기수 값 등과 같은 소스 코드 레이아웃에 대한 기타 세부 정보를 보관하는 경우 유용합니다.)
  • 모든 식별자의 범위와 의미를 보여주는 기호 테이블을 작성합니다.
  • 기능에서 제어 흐름을 추출할 수 있습니다.
  • 코드에서 데이터 흐름을 추출할 수 있습니다.
  • 시스템에 대한 통화 그래프를 구성할 수 있습니다.
  • 각 포인터가 가리키는 대상을 결정할 수 있습니다.
  • 위의 사실을 사용하여 사용자 정의 분석기를 구성할 수 있습니다.
  • 이러한 사용자 정의 분석에 따라 코드를 변환할 수 있습니다(일반적으로 구문 분석된 코드를 나타내는 AST를 수정함).
  • 수정된 AST에서 소스 텍스트(레이아웃 및 주석 포함)를 재생성할 수 있습니다.

이러한 기계를 사용하여 필요한 세부 수준의 분석을 구현한 다음 런타임 반사가 달성하는 효과를 얻기 위해 코드를 변환합니다.몇 가지 주요 이점이 있습니다.

  • 분석의 세부 수준 또는 양은 야망의 문제입니다(예: 런타임 리플렉션이 수행할 수 있는 작업에만 제한되지 않음).
  • 동작에 반영된 변경을 달성하기 위한 런타임 오버헤드가 없습니다.
  • 관련된 기계는 특정 언어 구현이 제공하는 것에 제한되지 않고 일반적이며 여러 언어에 걸쳐 적용될 수 있습니다.
  • 이것은 사용하지 않는 것에 대해 지불하지 않는다는 C/C++ 아이디어와 호환됩니다.반사가 필요하지 않다면, 이 기계는 필요하지 않습니다.그리고 여러분의 언어는 약한 성찰의 지적 짐을 내장할 필요가 없습니다.

C, Java 및 COBOL에 대해 위의 모든 작업을 수행할 수 있는 시스템과 C++에 대해 대부분의 작업을 수행할 수 있는 시스템은 DMS 소프트웨어 리엔지니어링 툴킷을 참조하십시오.

[EDIT 2017년 8월: 이제 C11 및 C++2017을 처리합니다.]

팁과 속임수는 항상 존재합니다.메타레스크 라이브러리 https://github.com/alexanderchuranov/Metaresc 를 살펴보십시오.

유형 선언을 위한 인터페이스를 제공하며 유형에 대한 메타데이터도 생성합니다.메타데이터를 기반으로 복잡도가 높은 객체를 쉽게 직렬화/직렬화할 수 있습니다.기본적으로 XML, JSON, XDR, 리스프 유사 표기법, C-init 표기법을 직렬화/직렬화할 수 있습니다.

다음은 간단한 예입니다.

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#include "metaresc.h"

TYPEDEF_STRUCT (point_t,
                double x,
                double y
                );

int main (int argc, char * argv[])
{
  point_t point = {
    .x = M_PI,
    .y = M_E,
  };
  char * str = MR_SAVE_XML (point_t, &point);
  if (str)
    {
      printf ("%s\n", str);
      free (str);
    }
  return (EXIT_SUCCESS);
}

이 프로그램은 출력됩니다.

$ ./point
<?xml version="1.0"?>
<point>
  <x>3.1415926535897931</x>
  <y>2.7182818284590451</y>
</point>

라이브러리는 Linux, MacOs, FreeBSD 및 Windows에서 최신 gcc 및 clang에 대해 잘 작동합니다.사용자 지정 매크로 언어는 옵션 중 하나입니다.사용자는 평소처럼 선언을 수행하고 DWARF 디버그 정보에서 형식 설명자를 생성할 수 있습니다.이는 빌드 프로세스의 복잡성을 증가시키지만 채택이 훨씬 쉬워집니다.

그것에 대한 속임수가 있습니까?팁 있어요?

컴파일러는 선택적으로 '디버거 기호 파일'을 생성할 수 있으며, 이 파일을 사용하여 코드를 디버깅할 수 있습니다.링커는 '맵 파일'을 생성할 수도 있습니다.

이러한 파일을 생성한 다음 읽는 것이 요령/팁일 수 있습니다.

C++ 응용 프로그램에 반영을 추가하려면 어떻게 해야 합니까? (스택 오버플로) 그리고 C++이 C의 "슈퍼셋"으로 간주된다는 사실, 저는 당신이 운이 없다고 말하고 싶습니다.

C++에 리플렉션(Stack Overflow)이 없는 이유에 대해서도 긴 답변이 있습니다.

나는 많은 것들에 대한 반성이 필요했습니다.struct는 C의 s입니다.
모든 구조체에 대한 설명이 포함된 xml 파일을 만들었습니다. 다행히 필드 유형은 원시 유형이었습니다.
템플릿을 사용했습니다(C++이 아님).template하려면 ) 자동성생class 자의에 struct세터/게터 방법과 함께.
의 각의에서class맵을 사용하여 문자열 이름과 클래스 구성원(구성원에 대한 포인터)을 연결했습니다.

반성 없이는 상상조차 할 수 없는 저의 핵심 기능을 새롭게 설계할 수 있는 길이 열렸기 때문에 반성을 사용한 것을 후회하지 않았습니다.
(BTW, 원시 데이터베이스를 사용하는 프로그램의 외부 보고서 생성기였습니다.)

그래서 코드 생성, 함수 포인터, 맵을 사용하여 반사를 시뮬레이션했습니다.

다음과 같은 옵션을 알고 있지만, 모든 옵션에는 비용과 많은 제한이 따릅니다.

  • 사용하다libdl(#include <dfcln.h>)
  • 다음과 같은 도구 호출objdump또는nm
  • 개체 파일을 직접 구문 분석합니다(해당 라이브러리 사용).
  • 파서를 사용하여 컴파일 시 필요한 정보를 생성합니다.
  • 링커를 "남용"하여 기호 배열을 생성합니다.

저는 단위 테스트 프레임워크를 좀 더 아래의 예로 사용할 것입니다. 왜냐하면 단위 테스트 프레임워크에 대한 자동 테스트 검색은 반사가 매우 유용한 전형적인 예이고, C에 대한 대부분의 단위 테스트 프레임워크는 부족한 것이기 때문입니다.

용사를 합니다.libdl(#include <dfcln.h>)(POSIX)

이라면 POSIX를 하여 약간의 을 할 수 .libdl플러그인은 그런 식으로 개발됩니다.

사용하다

#include <dfcln.h>

및 에 " 스코및링서에크소드서"로 표시됩니다.-ldl.

은 그면기능액수있다니습할세스에러다▁functions있▁to니▁then▁access습수 기능에 접근할 수 있습니다.dlopen(),dlerror(),dlsym()그리고.dlclose()런타임에 공유 개체를 로드하고 액세스/실행할 수 있습니다.그러나 기호 테이블에 쉽게 액세스할 수는 없습니다.

의 또 단점은 동적 로 로드되는 를 통해 로드됨)에 대한 입니다.dlopen()).

중입니다.nm또는objdump

도망칠 수도 있어요.nm또는objdump기호 테이블을 표시하고 출력을 구문 분석합니다.나를 위해.nm -P --defined-only -g xyz.o는 좋은 결과를 제공하며 출력을 구문 분석하는 것은 사소한 일입니다.각 줄의 첫 번째 단어인 기호 이름과 두 번째 단어인 횡단 유형에만 관심이 있습니다.

개체 이름을 정적으로 알지 못하는 경우(예: 개체가 실제로 공유 개체인 경우) 적어도 Linux에서는 '_'로 시작하는 기호 이름을 건너뛸 수 있습니다.

objdump,nm또는 유사한 도구를 POSIX 환경 외부에서도 사용할 수 있습니다.

개체 파일을 직접 구문 분석

개체 파일을 직접 구문 분석할 수 있습니다.이를 처음부터 구현하지 않고 기존 라이브러리를 사용하는 것이 좋습니다.이 이런식로의 방법입니다.nm,objdump ㅠㅠlibdl구됩니다볼. 코스드수있다의 소스 를 살짝 볼 수 .nm,objdump그리고.libdl그리고 그들이 하는 일을 어떻게 하는지 알아내기 위해 사용하는 도서관.

파서 포함

컴파일 시 필요한 반사 정보를 생성하여 개체 파일에 저장하는 파서 및 코드 생성기를 작성할 수 있습니다.그러면 많은 자유를 얻을 수 있고 원시적인 형태의 주석을 구현할 수 있습니다.이것이 AceUnit와 같은 일부 유닛 테스트 프레임워크가 하는 일입니다.

저는 간단한 C 구문을 다루는 파서를 작성하는 것이 꽤 사소한 일이라는 것을 알았습니다.C를 정말 이해하고 모든 사례를 처리할 수 있는 파서를 작성하는 것은 사소한 일이 아닙니다.따라서, 이것은 C 구문이 얼마나 이국적인지에 따라 반영하고자 하는 한계가 있습니다.

링커를 "남용"하여 기호 배열 생성

C에서 액세스할 수 있도록 특수 섹션에 반영할 기호를 참조하고 링커 구성을 사용하여 섹션 경계를 내보낼 수 있습니다.

여기서 N-의존성 주입을 C로 설명했습니다. 링커 정의 어레이보다 더 나은 방법은 무엇입니까?어떻게 작동하는지.

하지만 조심하세요, 이것은 많은 것들에 달려있고 휴대하기에 그리 좋지 않습니다.저는 이것만 시도해 보았습니다.GCC/ld모든 컴파일러/링커에서 작동하지 않는다는 것도 알고 있습니다.또한 데드 코드 제거는 사용자가 이것을 어떻게 부르는지 감지하지 못할 것이 거의 보장되므로, 데드 코드 제거를 사용할 경우 모든 반사된 기호를 진입점으로 추가해야 합니다.

함정

일부 메커니즘의 경우, 특히 심볼 배열을 생성하기 위해 링커를 "남용"할 때 데드 코드 제거가 문제가 될 수 있습니다.반사된 기호를 링커의 진입점으로 지정하여 해결할 수 있으며 기호의 양에 따라 유용하지 않을 수 있습니다.

결론

nm그리고.libdl실제로 꽤 좋은 결과를 줄 수 있습니다.이 조합은 Java의 Junit 3.x에서 사용하는 Reflection 수준만큼 강력할 수 있습니다.주어진 반사 수준은 명명 규칙에 의한 테스트 사례 발견을 포함하여 C에 대한 Junit 3.x 스타일 유닛 테스트 프레임워크를 구현하기에 충분합니다.

파서를 사용하는 것은 더 많은 일을 하고 직접 컴파일하는 개체로 제한되지만, 대부분의 힘과 자유를 제공합니다.주어진 반사 수준은 주석에 의한 테스트 사례 발견을 포함하여 C에 대한 Junit 4.x 스타일 단위 테스트 프레임워크를 구현하기에 충분할 수 있습니다.AceUnit은 정확히 이를 수행하는 C의 단위 테스트 프레임워크입니다.

구문 분석과 링커를 결합하여 기호 배열을 생성하면 매우 좋은 결과를 얻을 수 있습니다. 사용자의 환경이 너무 많이 제어되어 링커를 사용하여 이러한 방식으로 작업할 수 있습니다.

물론 모든 접근 방식을 결합하여 필요에 맞게 조각과 조각을 연결할 수 있습니다.

당신은 처음부터 그것을 스스로 구현할 필요가 있을 것입니다.스트레이트 C에서는 구조 및 복합 유형에 대한 런타임 정보가 전혀 없습니다.메타데이터는 단순히 표준에 존재하지 않습니다.

  1. C에 대한 반사를 구현하는 것이 훨씬 더 간단할 것입니다...왜냐하면 C는 단순한 언어이기 때문입니다.
  2. 필요에 따라 dlopen/dlsym을 호출하여 함수가 존재하는지 탐지하는 것과 같은 놀라운 프로그램에 대한 몇 가지 기본 옵션이 있습니다.
  3. tcc를 사용하여 자체 수정/확장이 가능한 코드를 생성하는 도구가 있습니다.
  4. 위의 도구를 사용하여 자체 코드 분석기를 만들 수 있습니다.

질문의 작성자와 비슷한 이유로 C-type-reflection-API와 C 리플렉션 그래프 데이터베이스 형식 및 리플렉션 메타데이터를 작성하는 clang 플러그인을 함께 작업하고 있습니다.

ASN.1용 매퍼, 함수 인수 프린터, 함수 프록시, 퍼저 등과 같은 직렬화 및 역직렬화 루틴을 작성하기 위해 C 리플렉션 API를 사용합니다.Clang과 GCC는 모두 AST에 대한 액세스를 허용하는 플러그인 API를 가지고 있지만 현재 C 리플렉션 메타데이터에 대한 표준 그래프 형식은 없습니다.

제안된 C 리플렉션 API는 Crefl:

https://github.com/michaeljclark/crefl

Crefl API는 C 구조 선언에 대한 반사 메타데이터에 대한 런타임 액세스를 제공하며, intentic, set, enum, struct, union, field(구성원), array, constant, variable의 임의 중첩 조합을 지원합니다.

  • 휴대용 반사 메타데이터를 위한 Crefl 반사 그래프 데이터베이스 형식입니다.
  • Creflang 플러그인은 라이브러리에서 사용하는 C 리플렉션 메타데이터를 출력합니다.
  • Crefl API는 C 리플렉션 메타데이터에 대한 작업 지향 쿼리 액세스를 제공합니다.

C reflection API는 intentic, set, enum, struct, union, field, array, constant, variable의 임의 중첩 조합을 지원하여 C 구조 선언에 대한 런타임 반사 메타데이터에 대한 액세스를 제공합니다.Crefl C 반사 데이터 모델은 본질적으로 ISO/IEC 9899:9999의 C 데이터 유형을 전사한 것입니다.

  • C 고유 데이터 유형입니다.
    • 정수형
    • 부동 소수점 유형.
    • 복소수 유형.
    • 부울 형식
  • 중첩 구조체, 결합, 필드 및 비트 필드
  • 배열 및 포인터
  • 유형def 유형 별칭
  • 열거 및 열거 상수
  • 함수 및 함수 매개변수
  • 상수, 변동성 및 제한 한정자
  • GNU-C를 사용하는 스타일 )__attribute__).

도서관은 여전히 진행 중인 작업입니다.그 희망은 C에서 반사 지원에 관심이 있는 다른 사람들을 찾는 것입니다.

파서와 디버그 기호는 좋은 아이디어입니다.그러나 C에는 실제로 배열이 없다는 것이 단점입니다.그냥 뭔가에 대한 조언일 뿐입니다.

예를 들어, 소스 코드를 읽어 char *가 문자, 문자열 또는 "근접" 길이 필드를 기준으로 고정된 바이트 배열을 가리키는지 알 수 있는 방법은 없습니다.이것은 자동화된 도구는 말할 것도 없고 인간 독자들의 문제입니다.

Java 또는 .Net과 같은 현대 언어를 사용하는 것이 어떻습니까?C보다 빠를 수도 있습니다.

언급URL : https://stackoverflow.com/questions/1353022/reflection-support-in-c

반응형