2015-01-19 2 views
0

Java로 작성된 라이브러리를 C 프로그래밍 언어로 이식하려고합니다. 자바 인터페이스를 위해, 나는 예를 들어, 대체 함수 포인터의 구조체를 사용하려는 :C에서 Java 일반 인터페이스 및 추상 데이터 유형 시뮬레이션

// Java code 
public interface ActionsFunction { 
    Set<Action> actions(Object s); 
} 

/* C code */ 
typedef struct ActionsFunction {  
    List* (*actions)(void* s);  
    void (*clear_actions)(struct List **list); /* Since C doesn't have garbage collector */ 
} ActionsFunction; 

내 질문은 : 그것은 적절한 솔루션인지, 어떻게 내가 일반적인 인터페이스를 시뮬레이션 할 수 있는지 여부 같은 :

public interface List <E> { 
    void add(E x); 
    Iterator<E> iterator(); 
} 

UPDATE :

나는 또 다른 문제에 직면해야 : 목록과 같은 일반적인 추상적 인 데이터 구조를 구현, 큐, 스택 등시 C 표준 라이브러리에는 이러한 구현이 부족합니다. 내 접근 방식은 클라이언트 코드가 그 데이터의 포인터를 그 크기와 함께 전달해야하므로 라이브러리가 그 타입을 지정하지 않고 라이브러리를 유지할 수있게 해준다. 한 번 더, 그건 내 생각이야. 나는 당신의 조언뿐만 아니라 기술을 구현할 필요가있다.

내 초기 포팅 코드에서 찾을 수 있습니다 https://github.com/PhamPhiLong/AIMA

일반 추상적 인 데이터 구조 유틸리티 하위 폴더에서 찾을 수 있습니다.

+0

흠, 어쩌면, 매크로와 함께 연주를? – fge

+1

전체 OO 기능을 원한다면 조금 더 할 필요가 있지만 응용 프로그램에는 필요하지 않을 수도 있습니다. [GObject] (https://en.wikipedia.org/wiki/GObject)와 같은 C 용 OO 프레임 워크를 살펴 보았습니까? Java의 제네릭은 실제로 정적으로 검사 된 유형 변환이므로 기본 포인터 만 사용할 수 있습니다. 마침내 당신의 영어는 제게 잘 들립니다. 사과 할 필요가 없다. – 5gon12eder

+2

C에서 Java generics를 시뮬레이트하려면 Java generics가 그다지 일반적이지 않다는 것을 기억하십시오. 콜 사이트에서 모든 캐스트를 삽입하기위한 문법적 설탕 일뿐입니다. – Deduplicator

답변

4

다음은 매크로를 사용하여 이와 같은 작업을 수행하는 간단한 예입니다. 이것은 털이 빠르지 만 빠르지 만 올바르게 수행되면 완전한 정적 유형 안전을 유지할 수 있습니다.

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

#define list_type(type)  struct __list_##type 

/* A generic list node that keeps 'type' by value. */ 
#define define_list_val(type)   \ 
    list_type(type) {     \ 
     list_type(type) *next;   \ 
     type value;      \ 
    } 

#define list_add(plist, node)      \ 
do             \ 
{             \ 
    typeof(plist) p;        \ 
    for (p = plist; *p != NULL; p = &(*p)->next) ; \ 
    *p = node;          \ 
    node->next = NULL;        \ 
} while(0) 

#define list_foreach(plist, p)      \ 
for (p = *plist; p != NULL; p = p->next) 


define_list_val(int) *g_list_ints; 
define_list_val(float) *g_list_floats; 


int main(void) 
{ 
    list_type(int) *node; 

    node = malloc(sizeof(*node)); 
    node->value = 42; 
    list_add(&g_list_ints, node); 

    node = malloc(sizeof(*node)); 
    node->value = 66; 
    list_add(&g_list_ints, node); 


    list_foreach(&g_list_ints, node) { 
     printf("Node: %d\n", node->value); 
    } 

    return 0; 
} 
+0

+1 "완벽한 정적 유형 안전을 유지할 수 있습니다." 이것은 제가 제안한 어떤 것에 대해서도이 방법을 사용하는 가장 큰 이유입니다. –

2

난 당신이 설명한 작업을 수행하려고에 다음 방법 중 하나 이상을 사용하는 기대 C.에서 일반적인 틱 프로그래밍을 할 수있는 몇 가지 일반적인 방법이 있습니다.

매크로 : 하나는 매크로를 사용하는 것입니다. 이 예에서, MAX 함수처럼 보이지만, ">"연산자와 비교 될 수있는 일에 운항합니다 :

#define MAX(a,b) ((a) > (b) ? (a) : (b)) 

int i; 
float f; 
unsigned char b; 
f = MAX(7.4, 2.5) 
i = MAX(3, 4) 
b = MAX(10, 20) 

VOID * : 또 다른 방법은, 일반 데이터를 표현하기위한 void * 포인터를 사용하는 것입니다 그런 다음 함수 포인터를 알고리즘에 전달하여 데이터를 조작하십시오. 이 기술의 고전적인 예를 보려면 <stdlib.h> 함수 qsort을 찾아보십시오.

유니온 스 : 또 다른 것으로, 덜 자주 볼 수도 있지만, 기술은 여러 유형의 데이터를 보유하기 위해 공용체를 사용하는 것입니다. 이것은 좀 추한하지만 데이터를 조작하고 많은 코딩 저장하지 않을 수 있습니다 알고리즘한다 :

enum { VAR_DOUBLE, VAR_INT, VAR_STRING } 

/* Declare a generic container struct for any type of data you want to operate on */ 
struct VarType 
{ 
    int  type; 
    union data 
    { 
     double d; 
     int i; 
     char * sptr; 
    }; 
} 

int main(){ 
    VarType x; 
    x.data.d = 1.75; 
    x.type = VAR_DOUBLE; 
    /* call some function that sorts out what to do based on value of x.type */ 
    my_function(x); 
} 

CLEVER 주조를 & 포인터 MATH 그것은 특정 종류의 동작 기능을 데이터 구조를 볼 수있는 아주 일반적인 관용구의 구조체의 다음 구조체에 포함 된에 의해 유용한 아무것도 할 구조체가 필요합니다.

쉬운 방법은 데이터 구조에 삽입 할 수있는 구조체가 파생 된 형식의 첫 번째 멤버가되도록하는 것입니다. 그런 다음 & 사이에 앞뒤를 매끄럽게 뒤집을 수 있습니다. 더 다양한 방법은 'offsetof'를 사용하는 것입니다. 다음은 간단한 예입니다.예를 들어

:

/* Simple types */ 
struct listNode { struct listNode * next; struct listNode * prev }; 
struct list { struct listNode dummy; } 

/* Functions that operate on those types */ 
int append(struct list * theList, struct listNode * theNode); 
listNode * first(struct list *theList); 

/* To use, you must do something like this: */ 

/* Define your own type that includes a list node */ 
typedef struct { 
    int x; 
    double y; 
    char name[16]; 
    struct listNode node; 
} MyCoolType; 

int main() { 
    struct list myList; 
    MyCoolType coolObject; 
    MyCoolType * ptr; 

    /* Add the 'coolObject's 'listNode' member to the list */ 
    appendList(&myList, &coolObject.node); 

    /* Use ugly casting & pointer math to get back you your original type 
     You may want to google 'offsetof' here. */ 
    ptr = (MyCoolType *) ((char*) first(&myList) 
      - offsetof(MyCoolType,node); 
} 

libev 문서는이 마지막 기술의 좀 더 좋은 예제가 있습니다

http://search.cpan.org/dist/EV/libev/ev.pod#COMMON_OR_USEFUL_IDIOMS_(OR_BOTH)

+0

답변이 매우 유용합니다. 이 질문에 대한 나의 의도는 기본적으로 클라이언트 코드가 라이브러리에서 호출 할 함수의 프로토 타입을 정의하는 Java 인터페이스를 이식하는 데 초점을 맞추고 있지만 C 표준 이후 기본 추상 데이터 구조를 구현할 때 직면해야하는 또 다른 문제를 상기시켜 주셨습니다. 라이브러리에는 목록, 대기열 등이 포함되어 있지 않습니다. 구현은 Java를 좋아합니다. 내 접근 방식은 각 ADS (단순히 함수 포인터의 구조체)에 대한 인터페이스를 만드는 것입니다. 라이브러리는 노드의 유형에주의를 기울일 필요가 없지만 크기에 수반되는 포인터를 고려해야합니다. –