Roby94 (Member)
Guru
Messaggi: 1170
Iscritto: 28/12/2009
|
Oramai buonanotte, ennesima esigenza al limite delle regole del C. Ho due librerie, che dovrebbe condividere gran parte se non tutti i prototipi, quindi condividono un header file incluso nel loro personale header file. Il problema, questi prototipi presentano tutti tra gli argomenti un tipo utente, che però non è completamente condiviso dalle librerie, per farla semplice sarà sempre un tipo con un nome ben preciso definito a partire da una struttura, ma la struttura dipende in una piccola parte dalla libreria.
header.h
Codice sorgente - presumibilmente C/C++ |
void proto1(type_t*);
void proto2(type_t*);
|
headerLibA.h
Codice sorgente - presumibilmente C++ |
#include "header.h" typedef struct { char x; float a, b } type_t;
|
headerLibB.h
Codice sorgente - presumibilmente C++ |
#include "header.h" typedef struct {char x; int c, d } type_t;
|
e poi negli specifici file sorgente delle librerie vengono inclusi i relativi header file.
Ora so che il compilatore pretende il tipo già definito per sapere quanta memoria allocare per le sue chiamate, ma in questo caso vi sono solo prototipi che richiamano la funzione, prima che queste vengano definiti il tipo sarà definito con precisione. Esiste un metodo alla extern per aggirare questa limitazione del compilatore? Ho girato in lungo e largo ma non è un problema comune e chi lo ha incontrato non ha trovato soluzioni soddisfacenti o almeno non le ha rese pubbliche.
Grazie in anticipo per ogni suggerimento. |
|
nessuno (Normal User)
Guru^2
Messaggi: 6404
Iscritto: 03/01/2010
|
Potresti usare una
union
tra le due struct
Ricorda che nessuno è obbligato a risponderti e che nessuno è perfetto ...
---
Il grande studioso italiano Bruno de Finetti ( uno dei padri fondatori del moderno Calcolo delle probabilità ) chiamava il gioco del Lotto Tassa sulla stupidità. |
|
Roby94 (Member)
Guru
Messaggi: 1170
Iscritto: 28/12/2009
|
Mhh grazie ma non credo di capire, come posso fare un union tra due tipi? Nel senso, io non ho idea di quante volte e che nomi assumeranno le variabili di tipo type_t.
Vorrei sottolineare che la mia è una necessità puramente organizzativa, cosi da non commettere errori e modificare un prototipo in una libreria e dimenticarmi di modificarlo nell'altra, cosi da poter garantire la quasi completa compatibilità tra le due, salvo per la funzione Init che si occupa appunto di inserire i dati nella struct.
Mi farebbe comodo qualcosa alla partial del C#.
Ultima modifica effettuata da Roby94 il 17/12/2015 alle 12:37 |
|
nessuno (Normal User)
Guru^2
Messaggi: 6404
Iscritto: 03/01/2010
|
Intendo che potresti usare questa
typedef struct { char x; union { float a; int c; } _u1; union { float b; int d; } _u2; } type_t;
Ricorda che nessuno è obbligato a risponderti e che nessuno è perfetto ...
---
Il grande studioso italiano Bruno de Finetti ( uno dei padri fondatori del moderno Calcolo delle probabilità ) chiamava il gioco del Lotto Tassa sulla stupidità. |
|
Thejuster (Admin)
Guru^2
Messaggi: 2306
Iscritto: 04/05/2008
|
Sbagliato a postare scusate
Ultima modifica effettuata da Thejuster il 17/12/2015 alle 18:21
|
|
lumo (Member)
Expert
Messaggi: 449
Iscritto: 18/04/2010
|
Ad occhio mi pare una cosa che il C++ risolverebbe con i template.
Comunque è difficile dare un giudizio generale senza sapere come stai usando quelle cose. Ad esempio, i due header possono essere inclusi contemporaneamente?
Le variabili all'interno della struttura sono accessibili all'utilizzatore oppure sono accessibili solo indirettamente?
Ad esempio la soluzione di nessuno va bene ma dovresti adattarla con un po' di boilerplate in modo che si "attacchi" alle implementazioni.
Idem per altre soluzioni che avrei in mente.
|
|
Template (Member)
Pro
Messaggi: 177
Iscritto: 09/12/2015
|
Forse è un'idea inadeguata (anche perchè quello che hai scritto non è che sia esposto in maniera chiarissima quindi non sono sicuro di sapere cosa tu voglia), ma... se usassi i puntatori?
Qualcosa come:
Codice sorgente - presumibilmente C++ |
typedef struct type_tA *tA; //Tipo di headerLibA typedef struct type_tB *tB; //Tipo di headerLibB void proto1(tA); void proto2(tB);
|
Questa procedura, che è praticamente standard nella creazione di tipi ADT (e che è molto simile a quella usata per creare le struct ricorsive), consente di avere riferimenti ai tipi di dato che ti servono senza per forza doverli predefinire: il puntatore ha dimensioni standard, perchè contiene sempre un indirizzo di memoria, quindi il compilatore non avrà problemi
Ultima modifica effettuata da Template il 18/12/2015 alle 16:23 |
|
Roby94 (Member)
Guru
Messaggi: 1170
Iscritto: 28/12/2009
|
Vedo interesse quindi rispiego tutto da capo e con piu precisione, tirando fuori un esempio reale.
Integrato ADXL345 supporta interfaccia I2C e SPI. La libreria si articola cosi:
Codice sorgente - presumibilmente Plain Text |
ADXL345.h
SPI\ADXL345SPI.h
SPI\ADXL345SPI.c
I2C\ADXL345I2C.h
I2C\ADXL345I2C.c
|
ADXl345.h
Codice sorgente - presumibilmente C++ |
#pragma once void ADXL345SetPower(ADXL345_t*, ADXL345Bandwidth_t, uint8_t); void ADXL345SetRange(ADXL345_t*, ADXL345Range_t, uint8_t); void ADXL345SetOffset(ADXL345_t*, int8_t, int8_t, int8_t); void ADXL345GetData(ADXL345_t*);
|
SPI/ADXL345SPI.h
Codice sorgente - presumibilmente C++ |
#pragma once #include "...\ADXL345.h" typedef struct { volatile uint8_t *port; uint8_t portN; int16_t x; int16_t y; int16_t z; } ADXL345_t; void ADXL345Init(ADXL345_t*, volatile uint8_t*, uint8_t);
|
I2C/ADXL345I2C.h
Codice sorgente - presumibilmente C++ |
#pragma once #include "...\ADXL345.h" typedef struct { uint8_t address; int16_t x; int16_t y; int16_t z; } ADXL345_t; void ADXL345Init(ADXL345_t*, uint8_t);
|
I file C implementano semplicemente i prototipi del relativo header file e i prototipi contenuti nel header principale.
Le due cartelle costituiscono di per se due librerie indipendenti, quindi o si include ADXL345SPI.h o ADXL345I2C.h, mai entrambi, il tutto serve per garantire la completa compatibilità tra le due interfacce, cosi da non dover modificare righe di codice nel caso del cambiamento della stessa.
Il problema di questo è che i prototipi nel file ADXL345.h non hanno senso per il compilatore, in quanto ADXL345_t non è ancora stato dichiarato quando il compilatore interpreta il file, verrà dichiarato nel l'header specifico della libreria. La soluzione union non mi piace un granche, non vorrei avere a progetto finito alcuna traccia dell'altra libreria nell'header file per non creare confusione inutile. Ripeto, a me servirebbe un costrutto che dicesse al compilatore, il tipo richiesto lo troverai piu avanti(non in fase di linking ma proprio in quella di compilazione).
|
|
Template (Member)
Pro
Messaggi: 177
Iscritto: 09/12/2015
|
Ora credo di aver capito meglio... e la soluzione che ti ho proposto io mi sembra adatta: riscrivi il file ADXL345.h così:
Codice sorgente - presumibilmente C++ |
typedef ADXL345_t *dato; typedef ADXL345Bandwidth_t *banda; typedef ADXL345Range_t *range; void ADXL345SetPower(dato, banda, uint8_t); void ADXL345SetRange(dato, range, uint8_t); void ADXL345SetOffset(dato, int8_t, int8_t, int8_t); void ADXL345GetData(dato);
|
In questo modo (notando solo che, invece di dati ADXL345Bandwidth_t o ADXL345Range_t, avrai in input nelle prime due funzioni dei puntatori) potrai tranquillamente gestire il tutto indipendentemente da quale libreria "accessoria" includerai
Ultima modifica effettuata da Template il 18/12/2015 alle 16:21 |
|