2017-09-15 1 views
-2

Ich bin ziemlich neu in C und C++. Ich habe die Aufgabe (es ist mehr für die Praxis), ein bestimmtes C-Modul in C++ zu ändern. Zu diesem Zweck muss ich zuerst die c-Dateien verstehen.Funktion Zeiger-Array: void ** Besetzung

Ich habe zwei spezifische Fragen, aber ich möchte Teile der Funktion in Kürze skizzieren. Ich versuche, allgemeine Identifikatoren zu verwenden.

Auszüge aus C-Code:

Es gibt einen Broker, die Funktionen Callbacks registrieren bietet. Der Broker hält die verschiedenen Callback-Typen in den entsprechenden Arrays.

Zunächst erklärten sie ein paar Funktionszeiger den Rückruf angeben:

typedef bool (*ReadRequestCallback_tpf) (param1 a, param2 b, param3 c); 
typedef bool (*ReadResponseCallback_tpf) (param4 a, param5 b); 
typedef bool (*WriteRequestCallback_tpf) (param6 a, param7 b, param8 c); 
... 

Dann machten sie Arrays für jede registrierte Rückrufe halten:

ReadRequestCallback_tpf ReadRequest_apf [MaxReadRequest]; 
ReadResponseCallback_tpf ReadResponse_apf [MaxReadResponse]; 
WriteRequestCallback_tpf WriteRequest_apf [MaxWriteRequest]; 

Es Funktionen gegeben sind neuen Rückruf registrieren:

void RegisterReadRequestCallback_v (ReadRequestCallback_tpf callback_pf){ 
    AddCallback_v((void**)ReadRequest_apf, (void*) callback_pf); 
} 
void RegisterReadResponseCallback_v (ReadResponseCallback_tpf callback_pf){ 
    AddCallback_v((void**)ReadResponse_apf, (void*) callback_pf); 
} 
void RegisterWriteRequestCallback_v (WriteRequestCallback_tpf callback_pf){ 
    AddCallback_v((void**)WriteRequest_apf, (void*) callback_pf); 
} 

Die Signatur von AddCallback_v ist wie:

void AddCallback_v (void* Array_apv[], void* function_pf) 

Meine Fragen:

  1. ist (void**) array_apf wirklich void* array_apv? Also ist die Umwandlung eines 'Array von Funktionszeigern' zu 'void-Zeiger auf void-Zeiger' gleich einem 'void-Zeiger zu einem Array von void-Zeiger'? Da es funktioniert, scheint es so. Aber ich verstehe es nicht wirklich.

  2. Wenn Sie versuchen, es (oder Teile) in C++ zu ändern, ist es eine bessere Möglichkeit, eine Vorlage anstelle der Besetzung zu verwenden (void *)?

Dies ist mein erster Eintrag hier. Ich hoffe, ich könnte meine Fragen erklären. Wenn etwas geklärt werden muss, lass es mich wissen.

Mit freundlichen Grüßen und vielen Dank im Voraus

+0

C und C++ sind nicht die gleiche Sprache, welche verwenden Sie eigentlich? – Barmar

+0

Der eigentliche Code ist in C geschrieben. Jeder Code-Auszug ist in C. In Zukunft sollte es in C++ geschrieben werden. – DanK0904

+1

anstelle des Arrays können Sie einen Vektor von std :: function versuchen –

Antwort

1

Der C-Code ist tatsächlich defekt.Während jeder Zeiger auf ein beliebiges Objekt kann auf einen Zeiger umgewandelt werden ungültig zu erklären, das ist nicht wahr für Zeiger auf Funktionen. Darüber hinaus gibt es keine Garantie, dass ein Zeiger auf eine Funktion neu interpretiert als Zeiger-to-Lücke in C sein kann, das bedeutet, dass die Funktion

void RegisterReadRequestCallback_v (ReadRequestCallback_tpf callback_pf){ 
    AddCallback_v((void**)ReadRequest_apf, (void*) callback_pf); 
} 

in vielerlei Hinsicht gebrochen ist, einschließlich, dass es bricht striktes Aliasing. Es ist einfach so falsch, dass es weh tut.

Die Absicht davon ist anscheinend, dass es eine generische Funktion gibt, die AddCallback_v benannt wird, die einen Zeiger auf das Rückruffeld und eine neue Rückruffunktion erhält, aber C garantiert nicht, dass das so funktionieren würde!

In C wäre der richtige Weg, um dies zu kodieren wäre Readrequest_apf usw. Arrays von generischen sein Zeiger auf Funktionen; das wäre zurückgeworfen auf ReadRequestCallback_tpf et al vor ihnen nennen, dh

typedef bool (*GenericCallback_tpf)(); 

GenericCallback_tpf ReadRequest_apf[MaxReadRequest]; 

void AddCallback_v(GenericCallback_tpf callback_array[]); 

void RegisterReadRequestCallback_v (ReadRequestCallback_tpf callback_pf){ 
    AddCallback_v(ReadRequest_apf, (GenericCallback_tpf)callback_pf); 
} 

Und beim Aufruf:

((ReadRequestCallback_tpf)ReadRequest_apf[i])(param1, param2, param3); 

In C++ würden Sie verwenden, um einen Vektor functors für jede von diesen *_apf; und deshalb würde ich keine Gussformen brauchen.

1
  1. Wenn ein Array an eine Funktion übergeben wird, wird er automatisch auf einen Zeiger auf das erste Element umgewandelt. In einer Funktionsdeklaration entspricht TYPE array[]TYPE *array. Daher entspricht void *array[]void **array.

  2. Einer der Zwecke von Templates ist es, die Verwendung eines void * Typs für generische Funktionen zu vermeiden, da der Compiler nicht sicherstellen kann, dass Sie ihn beim Verwenden des Zeigers zurück auf den ursprünglichen Typ konvertieren. Also ja, Vorlagen sind oft eine bessere Lösung als Funktionen, die void* Parameter übernehmen.