Grundlegende Frage zu C und Pointern

20 views
Skip to first unread message

Marco Feltmann <Coding>

unread,
Feb 6, 2014, 3:21:29 AM2/6/14
to cocoah...@googlegroups.com
Hallo Gemeinde, hallo Rainer. ;)

Xcode treibt mich gerade in den Wahnsinn. Ich muss für die PJSIP Library(1) einen Wrapper basteln, der idealerweise unter iOS und Android gleichermaßen funktioniert.
Also dachte ich mir 'Marco, schreib den allgemeinen Kram in C und kapsel das Ganze dann in wenige spezifische Wrapper.'

Nun stelle ich fest, dass die eigene Implementierung des SIP User Agents in der Library nicht meinen Ansprüchen genügt. Beziehungsweise den Ansprüchen der Gegenstelle.
Also mag ich mir einen eigenen User Agent bauen.

Und dort hapert es bereits ganz früh. Ich muss zur Erstellung eines Endpunkts (dem Herzstück des Ganzen) zunächst einen Memory Pool erstellen lassen, der mich bei der Speicherverwaltung unterstützt.
Die Funktion zur Erstellung des Pools schiebt ein generiertes struct in eine via Pointer übergebene Adresse.

Mein erster Ansatz war völlig naiv und führte natürlich zu einem EXC_BAD_ACCESS:
--
pj_caching_pool * internalCachingPool; // EXC_BAD_ACCESS, da Speicheradresse nicht initialisiert
pj_caching_pool_init(&internalCachingPool, &pj_pool_factory_default_policy, 1000);
--

Mein zweiter Ansatz hingegen führt zu einem "Variable has incomplete type 'pj_caching_pool' (aka 'struct pj_caching_pool')"
--
pj_caching_pool internalCachingPool = NULL; // Xcode Fehler, da offenbar unpassende Zuweisung.
pj_caching_pool_init(&internalCachingPool, &pj_pool_factory_default_policy1000);
--

Schlussendlich konnte ich in diesem speziellen Fall durch Zuhilfenahme der Informationen aus dem Header den Fehler loswerden.
--
pj_caching_pool internalCachingPool = {NULL, NULL, 0, 0, NULL, NULL, NULL, NULL, NULL};
pj_caching_pool_init(&internalCachingPool, &pj_pool_factory_default_policy, 1000);
--

Nur beim pjsip_endpoint bekomme ich es offenbar nicht hin die Struktur nachzubilden.
Die Struktur dessen versteckt sich in der sip_endpoint.c und selbst wenn ich die 15 Pointer innerhalb der Struktur auf NULL setze bekomme ich weiterhin die 'incomplete type' Fehlermeldung.
--
// Auszug aus der sip_endpoint.c
/**
 * The SIP endpoint.
 */
struct pjsip_endpoint
{
    pj_pool_t *pool;
    pj_mutex_t *mutex;
    pj_pool_factory *pf;
    pj_str_t name;
    pj_timer_heap_t *timer_heap;
    pjsip_tpmgr *transport_mgr;
    pj_ioqueue_t *ioqueue;
    pj_status_t ioq_last_err;
    pjsip_resolver_t *resolver;
    pj_rwmutex_t *mod_mutex;
    pjsip_module        *modules[PJSIP_MAX_MODULE];
    pjsip_module module_list;
    pjsip_hdr cap_hdr;
    pjsip_hdr req_hdr;
    exit_cb exit_cb_list;
};

// Meine Zuweisung mit dem Fehler
pjsip_endpoint endpoint = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
--

Ich könnte jetzt anfangen die einzelnen Werte anzupassen. Also statt NULL als name ein {"unnamed", 7} einzutragen etc.pp.
Allerdings frage ich mich ernsthaft, ob es da eine einfachere Möglichkeit gibt.

Hat da jemand einen Tipp/eine Idee für mich?

Gruß
Marco

Rainer Schmid

unread,
Feb 6, 2014, 3:37:42 AM2/6/14
to cocoah...@googlegroups.com
> [...]
> Mein zweiter Ansatz hingegen führt zu einem "Variable has incomplete
> type 'pj_caching_pool' (aka 'struct pj_caching_pool')"
> --
> pj_caching_pool internalCachingPool = NULL; // Xcode Fehler, da
> offenbar unpassende Zuweisung.

NULL ist ja ein Null-Pointer und internalCachingPool ist kein Pointer.

> [...]
> Schlussendlich konnte ich in diesem speziellen Fall durch Zuhilfenahme
> der Informationen aus dem Header den Fehler loswerden.
> --
> pj_caching_pool internalCachingPool = {NULL, NULL, 0, 0, NULL, NULL,
> NULL, NULL, NULL};
> pj_caching_pool_init(&internalCachingPool,
> &pj_pool_factory_default_policy, 1000);
> --

Brauchst Du überhaupt die explizite Initialisierung? Ist es bei C nicht
sowieso der default, dass Structs mit Nullen initialisiert werden (bin
mir da nie ganz sicher)?

Und erwartet pj_caching_pool_init() überhaupt ein Struct das
initialisiert ist, oder ist die Funktion eher dazu da, das Struct
sinnvoll zu intialisieren?


> Nur beim pjsip_endpoint bekomme ich es offenbar nicht hin die Struktur
> nachzubilden.
> [...]

Solltest Du das überhaupt? Die Doku sieht eigentlich eher aus, dass Du
mittels pjsip_endpt_create() so ein pjsip_endpoint struct erzeugen
solltest und nicht selber direkt.

Rainer

Rainer Schmid

unread,
Feb 6, 2014, 3:44:55 AM2/6/14
to cocoah...@googlegroups.com
>> Nur beim pjsip_endpoint bekomme ich es offenbar nicht hin die
>> Struktur nachzubilden.
>> [...]
>
> Solltest Du das überhaupt? Die Doku sieht eigentlich eher aus, dass
> Du mittels pjsip_endpt_create() so ein pjsip_endpoint struct erzeugen
> solltest und nicht selber direkt.

Also um es klarer zu machen, ich denke Du solltest so etwas wie

pjsip_endpoint *endpoint = NULL;
pjsip_endpt_create(..., &endpoint);

verwenden, um das struct auf dem Heap zu erzeugen. D.h. wenn ich die
Doku auf die schnelle richtig verstehe, sollte dann endpoint auf so ein
pjsip_endpoint Struct zeigen, was die Bibliothek erzeugt (und
initialisiert) hat.

Rainer

Marco Feltmann <Coding>

unread,
Feb 6, 2014, 4:05:13 AM2/6/14
to cocoah...@googlegroups.com
Gut, das kürzt das Ganze ein wenig ab. :)

Habe ich bereits probiert:
--
    pj_caching_pool internalCachingPool;
    pjsip_endpoint * endpoint = NULL;
    printf("Initializing...\n");

    

    pj_caching_pool_init(&internalCachingPool, &pj_pool_factory_default_policy, 1000);
    printf("Got pool @%p...\n", &internalCachingPool);

    

    pjsip_endpt_create((pj_pool_factory *)&internalCachingPool, "My own beautiful endpoint", &endpoint);
    printf("Got endpoint @%p...\n", &endpoint);
--
In dem Fall bekomme ich das besagte EXC_BAD_ACCESS.
Es knallt gemäß Stacktrace im pthread_getspecific.

Auch ist es mir nicht möglich beim pjsip_endpoint so wie beim Caching Pool zu verfahren.
Mein Ansatz dafür wäre der Folgende gewesen:
--
    pjsip_endpoint endpoint; // Variable has incomplete type 'pjsip_endpoint' (aka 'struct pjsip_endpoint')
    pjsip_endpoint * pEndpoint = &endpoint;

    pj_caching_pool internalCachingPool;
    printf("Initializing...\n");
    
    pj_caching_pool_init(&internalCachingPool, &pj_pool_factory_default_policy1000);
    printf("Got pool @%p...\n", &internalCachingPool);

    
    pjsip_endpt_create((pj_pool_factory *)&internalCachingPool, "My own beautiful endpoint", &endpoint);
    printf("Got endpoint @%p...\n", &endpoint);
--

Ich fürchte das liegt daran, dass pjsip_endpoint in der sip_endpoint.c definiert ist und nicht im öffentlichen Header steht. (Im Gegensatz zu pj_caching_pool)

Allerdings ist es auch durchaus wahrscheinlich, dass der Fehler eigentlich gar nicht in dem Pointer liegt sondern irgendwo anders.
Insofern werde ich mal schauen, ob ich den User Agent der Library als Vorlage zweckentfremden kann.

Auf jeden Fall schon einmal vielen Dank für die hilfreiche Unterhaltung.
Daran bilde ich mir ein zu erkennen, dass ich das mit dem Pointern im Prinzip schon einigermaßen verstanden habe und EXC_BAD_ACCESS nicht unbedingt heißen muss, dass ich bei der Definition der Pointer einen Fehler gemacht haben muss. :)

Daniel

unread,
Feb 6, 2014, 4:08:07 AM2/6/14
to cocoah...@googlegroups.com, cocoah...@googlegroups.com
> Am 06.02.2014 um 09:37 schrieb "Rainer Schmid" <r...@outside-of-the-asylum.de>:
>
> Brauchst Du überhaupt die explizite Initialisierung? Ist es bei C nicht sowieso der default, dass Structs mit Nullen initialisiert werden (bin mir da nie ganz sicher)?

Jein:
Man muß nicht alle Felder explizit setzen, aber dem struct einen literalen Wert zuweisen.

Soll heißen:
struct bad_ass_struct_with_gobs_of_fields b = {};

Gibt dir eine Variable „b“, die ein Bad–ass struct mit vielen Feldern ist, die alle zu 0 initialisiert wurden. Ohne die Zuweisung am Ende hätte man allerdings besagte Variable mit Tonnen von Müll in ihren Feldern.

Sind Deklaration und Definition der Variable nicht an derselben Stelle, (aber: warum?) kann man das leere struct-Literal auf den gewählten Typ casten.

Wem das nicht geheuer ist, der kann aber auch mit bzero(&b, sizeof(struct bad_ass_struct_with_gobs_of_fields)) (modulo Reihenfolge der Parameter) arbeiten.

Grüßle

Daniel

Daniel

unread,
Feb 6, 2014, 4:18:24 AM2/6/14
to cocoah...@googlegroups.com, cocoah...@googlegroups.com
Für deinen konkreten Fall bringt das aber nichts, da (wie Rainer schon anmerkte) Du eben nicht den struct erzeugen sollst um dann einen Pointer darauf zu erzeugen, und dann dessen Adresse in die Funktion zu stecken, sondern eigentlich solltest du mit

Typ *meins;
Funktion(Blabla, &meins); das bekommen was du willst.

Den Compilerfehler bekommst Du übrigens, weil Typ ein „opakes“ struct ist—wie z.B. NSString (OHNE „*“!).

Grüßle

Daniel
> --
> Sie erhalten diese Nachricht, weil Sie Mitglied der Google Groups-Gruppe "Cocoaheads Hamburg" sind.
> Um Ihr Abonnement für diese Gruppe zu beenden und keine E-Mails mehr von dieser Gruppe zu erhalten, senden Sie eine E-Mail an cocoaheads-h...@googlegroups.com.
> Wenn Sie Nachrichten in dieser Gruppe posten möchten, senden Sie eine E-Mail an cocoah...@googlegroups.com.
> Gruppe besuchen: http://groups.google.com/group/cocoaheads-hh
> Weitere Optionen: https://groups.google.com/groups/opt_out

Rainer Schmid

unread,
Feb 6, 2014, 4:28:06 AM2/6/14
to cocoah...@googlegroups.com
> [...]
> Habe ich bereits probiert:
> --
> pj_caching_pool internalCachingPool;
> pjsip_endpoint * endpoint = NULL;
> printf("Initializing...\n");
>
> pj_caching_pool_init(&internalCachingPool,
> &pj_pool_factory_default_policy, 1000);
> printf("Got pool @%p...\n", &internalCachingPool);
>
>
> pjsip_endpt_create((pj_pool_factory *)&internalCachingPool, "My own
> beautiful endpoint", &endpoint);
> printf("Got endpoint @%p...\n", &endpoint);
> --
> In dem Fall bekomme ich das besagte EXC_BAD_ACCESS.
> Es knallt gemäß Stacktrace im pthread_getspecific.

Das wird vermutlich meine letzte Antwort (da ich mich mit der Bibliothek
nicht auskenne, kann ich auch nur raten), aber von der Doku würde ich
fast darauf tippen, dass die Zeile

pjsip_endpt_create((pj_pool_factory *)&internalCachingPool, "My own
beautiful endpoint", &endpoint);

eher

pjsip_endpt_create(internalCachingPool.factory, "My own beautiful
endpoint", &endpoint);

lauten sollte (d.h. um das ganze objekt-orientiert auszudrücken: dieses
pj_caching_pool Struct ist keine pj_pool_factory, sondern hat eine
Member-Variable für die Factory).

Rainer

Marco Feltmann <Coding>

unread,
Feb 6, 2014, 6:00:20 AM2/6/14
to cocoah...@googlegroups.com
Vielen Dank ihr zwei. :)

Am 06.02.2014 um 10:28 schrieb Rainer Schmid <r...@outside-of-the-asylum.de>:

> Das wird vermutlich meine letzte Antwort (da ich mich mit der Bibliothek nicht auskenne, kann ich auch nur raten), aber von der Doku würde ich fast darauf tippen, dass die Zeile
>
> pjsip_endpt_create((pj_pool_factory *)&internalCachingPool, "My own beautiful endpoint", &endpoint);
>
> eher
>
> pjsip_endpt_create(internalCachingPool.factory, "My own beautiful endpoint", &endpoint);
>
> lauten sollte (d.h. um das ganze objekt-orientiert auszudrücken: dieses pj_caching_pool Struct ist keine pj_pool_factory, sondern hat eine Member-Variable für die Factory).

Das ist ein guter Tipp, der allerdings im Nachhinein auch zu EXC_BAD_ACCESS an derselben Stelle in pjthread_getspecific führte.
Bevor ich also den Ansatz des komplett eigenen User Agents weiter verfolge, schaue ich lieber einmal nach, was ich mit dem ganzen Modularaufbau der Library so gerissen bekomme.
Offenbar muss ich mich gar nicht komplett darauf verlassen, dass die Implementierung des User Agent alles richtig macht sondern kann mich vor und nach jede denkbare Aktivität klemmen.

Ich hoffe, dass ich so das Ziel erreicht bekomme und mich nicht unnötig lange mit Pointern auf Pointern herumärgern muss.

Immerhin habe ich dank euch gelernt, dass sich ein Struct ziemlich zügig mit leeren Werten initialisieren lässt, indem man myStruct = {} tippt.
Reply all
Reply to author
Forward
0 new messages