나는 동적 타입 언어를 쓰고 있습니다. 현재 내 개체는이 방식으로 표현된다 :C 언어의 동적 타이핑 표현하기
struct Class { struct Class* class; struct Object* (*get)(struct Object*,struct Object*); };
struct Integer { struct Class* class; int value; };
struct Object { struct Class* class; };
struct String { struct Class* class; size_t length; char* characters; };
목표는 내가 struct Object*
로 주변의 모든 것을 통과 할 수 있어야한다는 것입니다 후 class
속성을 비교하여 객체의 유형을 발견 할 수 있습니다. 예를 들어, 단순히 다음을 수행 할 사용하는 정수를 캐스팅 (integer
유형 struct Class*
의라고 가정) :
struct Object* foo = bar();
// increment foo
if(foo->class == integer)
((struct Integer*)foo)->value++;
else
handleTypeError();
문제는 내가 아는 한, C 표준에 대한 어떤 약속을하지 않으며,이다 구조가 저장되는 방법. 내 플랫폼에서이 작동합니다. 그러나 다른 플랫폼에서 struct String
은 class
전에 value
을 저장할 수 있으며 위의 경우 foo->class
에 액세스했을 때 실제로는 foo->value
에 액세스 할 수 있습니다. 이는 분명히 나쁩니다. 이식성은 여기서 큰 목표입니다.
이 방법의 대안이 있습니다
struct Object
{
struct Class* class;
union Value
{
struct Class c;
int i;
struct String s;
} value;
};
여기서 문제는 노조가 노조에 저장 될 수있는 가장 큰 물건의 크기만큼의 공간을 사용한다는 것입니다. 내 유형 중 일부가 내 다른 유형보다 몇 배나 크기 때문에 내 소형 유형 (int
)이 허용 할 수없는 절충점 인 큰 유형 (map
)만큼의 공간을 차지한다는 것을 의미합니다.
struct Object
{
struct Class* class;
void* value;
};
이렇게하면 작업 속도가 느려지는 수준의 리디렉션이 생성됩니다. 속도가 목표입니다.
마지막 대안은 void*
초를 전달하고 구조의 내부를 직접 관리하는 것입니다. 예를 들어, 위에서 언급 한 형식 시험을 구현하는이 나에게 내가 원하는 모든 것을 (휴대 성, 다양한 유형에 대해 서로 다른 크기 등)을 제공하지만, 적어도 두 가지 단점이있다
void* foo = bar();
// increment foo
if(*((struct Class*) foo) == integer)
(*((int*)(foo + sizeof(struct Class*))))++;
else
handleTypeError();
:
- 무시 무시한를 위의 코드는 단일 멤버 오프셋 만 계산합니다. 정수보다 복잡한 유형에서는 훨씬 더 나 빠지게됩니다. 매크로를 사용하여 조금 완화 할 수는 있지만, 문제가 발생하더라도 문제가 될 수 있습니다.
- 개체를 나타내는
struct
이 없으므로 스택 할당 옵션을 사용할 수 없습니다 (적어도 힙에 자체 스택을 구현하지 않고는).
기본적으로 내 질문은 내가 원하는 것을 어떻게 지불 할 수 있습니까? 이식성이 있고 다양한 유형의 크기가 다르며 리디렉션을 사용하지 않고 내 코드를 꽤 유지할 수있는 방법이 있습니까?
EDIT : 이것은 내가 SO 질문에 대해받은 최고의 응답입니다. 대답을 선택하는 것은 어려웠습니다. 그래서 내가 하나의 대답을 선택하도록 허락 했으므로 나를 내 해결책으로 인도하는 사람을 선택했으나 모두 상향 투표를 받았다.
링크를 제공해 주셔서 감사합니다. 나는 그것으로 많은 것을 배웠다. – Imagist
귀하의 링크에 따르면, 귀하의 코드보다 간접적 인 방법으로이 작업을 수행 할 수 있습니다. 구체적으로 : "[struct]는'int'로 시작하고'struct *'는'int *'로 형변환되어 int 값을 첫 번째 필드에 쓸 수 있습니다." 즉,이 경우'struct Integer *'는'struct Class **'로 형변환 될 수 있습니다. 즉, 선언문을 변경할 필요가 없습니다. 포인터를 통해 클래스를 참조하면됩니다. (어쨌든 주위를 전달하는 방법입니다.) – Imagist