Brauche Tip für: gleiche Typdefinition in zwei unterschiedlichen APIs



  • Hallo Forum,

    habe folgendes Problem.
    Mein Program welches in C geschrieben läuft auf einem Lotus Domino Server. Für den Zugriff auf den Domino Server gibt es eigens eine C-API von IBM. Jetzt soll dieses Progeamm auch an einen MySQL Server angebunden werden. Dazu verwende ich wieder eine C-API, diesmal die für MySQL.
    Sobald ich aber beide C-APIs in mein Programm include erhalte ich

    e:\DomSpamC\DSC-Suite\NotesApi\include\global.h(1121) : error C2371: 'LIST': Neudefinition; unterschiedliche Basistypen
    e:\domspamc\dsc-suite\dscglobal\include\mysql\my_list.h(26): Siehe Deklaration von 'LIST'

    Okay, beide C-APIs definieren einen Typ names LIST.
    Kann mir jemand sagen, wie ich es schaffe beide APIs zu verwenden?
    Mir schwant da Übles: gibt's deswegen vielleicht Bibliotheken? Wenn ja, hat vielleicht jemanden nen kurzen Tip/Link parat?

    Gruß

    NicoP.



  • ^^könntest du nicht einfach einen umbenennen? wenn die APIs schon kompilierte libraries sind, merken sie ja nichts davon.
    🙂



  • naja, den weg hab ich anfangs schon versucht. aber da komm ich nicht zum ziel. die werden an so vielen stellen verwendet und irgendwann verliere ich dann den überblick. 😞



  • vielleicht hilft dir ein refactoring tool? für C gibt's auch was. vielleicht das: http://www.spinellis.gr/cscout/index.html ?
    (hab's selbst aber nicht ausprobiert).
    🙂



  • ich muss aber auch noch zugeben, dass ich beide APIs nur sehr ungerne anpassen würde. gerade bei der Lotus API kommen fast halbjährlich neue releases raus, die ich ja dann jedesmal ändern müsste.



  • ^^wie sehen denn die beiden definitionen aus? poste sie doch mal hier. wenn's #defines sind, könnte man vielleicht mit #undef was machen. ansonsten fällt mir auch kein besserer trick ein.
    🙂



  • my_list.h (MySQL)

    #ifndef _list_h_
    #define _list_h_
    
    #ifdef	__cplusplus
    extern "C" {
    #endif
    
    typedef struct st_list {
      struct st_list *prev,*next;
      void *data;
    } LIST;
    ...
    

    global.h (Lotus C-API)

    ...
    /*	List structure */
    
    typedef struct {
    	USHORT ListEntries;			/* list entries following */
    								/* now come the list entries */
    } LIST;
    ...
    

    Generell könnte ich die MySQL-Schnittstelle doch aber auch in eine eigenständige Bibliothek auslagern? Wie aufwendig ist den sowas? Kenn mich damit bisher noch nicht aus. Allerdings müsste ich das sowohl für Win32 als auch für Linux vorsehen, da ich bisher beide Plattformen mit meinem Programm bediene.



  • Eventuell kannst du dein Programm etwas modularer aufbauen, so dass du nicht von der selben Quelldatei aus beide APIs benötigst.

    Und ansonsten könntest du den doppelten Bezeichner einfach mit dem Präprozessor um#definieren, also

    #define LIST LIST_1
    #include <erste_api.h>
    #undef LIST
    
    #define LIST LIST_2
    #include <zweite_api.h>
    #undef LIST
    


  • So, ich habe mich für einen modularen Programmaufbau entschieden.
    Da ich allerdings keine Erfahrung damit habe wollte ich mein Ergebnis von Euch nochmal bewerten lassen.

    DSCSync.c (mein MySQL-Modul welches die Kommunikation zur MySQL-Datenbank übernimmt)

    #define MAX_LOG_CHAR		150
    
    #include "winsock2.h"
    #include "stdio.h"
    
    #include "DSCSync.h"
    
    int MySQLConnect(struct MySQLSettings *MySQLSettings, char szClientVersion[], char szServerVersion[], int intStringSize)
    {
    	MYSQL	*mysql = NULL;
    
    	_snprintf( szClientVersion, intStringSize, "%s", mysql_get_client_info());
    
    	if((mysql=mysql_init(mysql))==NULL)
    	{
    		return FALSE;
    	}
    
    	/*now you can call any MySQL API function you like*/
    	if (!mysql_real_connect(mysql, MySQLSettings->szHost, MySQLSettings->szUser, MySQLSettings->szPW, MySQLSettings->szDB,0,NULL,0))
    	{
    //		_snprintf( strTemp, intStringSize, "Failed to connect to MySQL: Error: %s", mysql_error(mysql));
    		return FALSE;
    	}
    
    	_snprintf( szServerVersion, intStringSize, "%s", mysql_get_server_info(mysql));
    
    	mysql_close(mysql);
    
    	return TRUE;
    }
    

    DSCSync.h (zugehörige Header-Datei)

    #include "mysql/mysql.h"
    
    #ifndef DSCMYSQL_T
    #define DSCMYSQL_T
    typedef struct MySQLSettings
    {
    	char			*szHost;
    	char			*szDB;
    	char			*szUser;
    	char			*szPW;
    } MySQLSettings;
    #endif
    
    int MySQLConnect(struct MySQLSettings *MySQLSettings, char szClientVersion[], char szServerVersion[], int intStringSize);
    

    DSCTest.c (mein Program welches die Lotus-C-API inkludiert und die DSCSync.c zur Verbindung zum MySQL-Server nutzt)

    int PeriodicSynchronizePart( )
    {
    	char	strTemp[150];
    
    	char szClientVersion[MAX_LOG_CHAR];
    	char szServerVersion[MAX_LOG_CHAR];
    
    	if (g_DSCConfig.MySQLSettings.szHost == NULL)
    	{
    		/* mandatory MySQL settings not specified, so exit gracefully */
    		return FALSE;
    	}
    
    	if (MySQLConnect(&g_DSCConfig.MySQLSettings, szClientVersion, szServerVersion, MAX_LOG_CHAR))
    	{
    
    		_snprintf( strTemp, MAX_LOG_CHAR, "%s %s", INFO_MSG_DSCLEARNER_1, szClientVersion);
    		WriteToNotesLog( strTemp, 0, g_DSCConfig.Debug );
    
    		_snprintf( strTemp, MAX_LOG_CHAR, "%s %s", INFO_MSG_DSCLEARNER_2, szServerVersion);
    		WriteToNotesLog( strTemp, 0, g_DSCConfig.Debug );
    
    	}
    
    	return TRUE;
    }
    

    DSCTest.h

    ...
    #ifndef DSCMYSQL_T
    #define DSCMYSQL_T
    typedef struct MySQLSettings
    {
    	char			*szHost;
    	char			*szDB;
    	char			*szUser;
    	char			*szPW;
    } MySQLSettings;
    #endif
    
    #ifndef SPAMCCONFIG_T
    #define SPAMCCONFIG_T
    typedef struct SpamCConfig
    {
    ...
    	struct		MySQLSettings MySQLSettings;	/* structure to MySQL settings */
    } SpamCConfig;
    
    ...
    
    ...
    

    Funktional ist das Ganze. Nur macht man die Modularisierung so (auch: doppelte Typedefinition von MySQLSettings)?

    Wäre echt dankbar für eure Kritik.

    NicoP.



  • Die doppelte Typdefinition ist seltsam.

    Eine Struct- oder Typdefinition steht normalerweise nur in einer Headerdatei(*), zusammen mit den zugehörigen Funktionsdefinitionen. Andere Module (also .c-Dateien), die diesen Typ benutzen wollen, includen dann einfach diese Datei.

    D.h. MySQLSettings sollte nicht nochmal in DSCTest.h definiert werden, sondern stattdessen sollte DSCSync.h von DSCTest.c includet werden, so dass der Typ und die Funktion MySQLConnect dort verwendet werden können.

    Und das #include "mysql/mysql.h" sollte nicht in DSCSync.h, sondern in DSCSync.c stehen, denn ansonsten hast du wieder das ursprüngliche Problem.

    (* Noch schöner ist es, wenn die eigentlich Struktur in gar keiner Header-Datei steht, sonder nur ein Pointer darauf in einer Headerdatei als Typ definiert wird. Siehe http://en.wikipedia.org/wiki/Opaque_pointer )

    Edit: Achso, da MySQLSettings auch schon in DSCTest.h gebraucht wird, müsste DSCSync.h dort schon included werden.



  • "Opaque pointer", ich glaube das war der Hinweis den ich gesucht habe. Wenn ich's umgesetzt habe melde ich mich wieder.

    Dankeschön! 🙂


Anmelden zum Antworten