Domanda

Ho una funzione C in una libreria statica, chiamiamola A, con la seguente interfaccia:

int A(unsigned int a, unsigned long long b, unsigned int *y, unsigned char *z);

Questa funzione cambierà il valore di y an z (questo è sicuro). Lo uso da una libreria C ++ dinamica, usando extern " C " ;.

Ora, ecco cosa mi stordisce:

  • y è impostato correttamente, z non è cambiato. Quello che intendo esattamente è che se entrambi sono inizializzati con un valore (puntato) di 666, il valore indicato da y sarà cambiato dopo la chiamata ma non il valore indicato da z (ancora 666).
  • quando chiamata da un binario C, questa funzione funziona senza problemi (valore è indicato da z è modificato).
  • se creo una libreria C fittizia con una funzione con lo stesso prototipo e la utilizzo dalla mia libreria dinamica C ++, funziona molto bene. Se riutilizzo le stesse variabili per chiamare A (..), ottengo lo stesso risultato di prima, z non viene modificato.

Penso che i punti precedenti mostrino che non è uno stupido errore con la dichiarazione delle mie variabili.

Sono chiaramente bloccato e non posso cambiare la libreria C. Hai qualche idea su quale possa essere il problema? Stavo pensando a un problema sull'interfaccia C / C ++, ad esempio il modo in cui un carattere * viene interpretato.

Modifica: ho finalmente scoperto qual era il problema. Vedi sotto la mia risposta.

È stato utile?

Soluzione 9

Prima di tutto, sono molto grato a tutti per il vostro aiuto. Grazie alle numerose idee e indizi che mi hai dato, sono stato finalmente in grado di risolvere questo problema. I tuoi consigli mi hanno aiutato a mettere in discussione ciò che ho dato per scontato.

Risposta breve al mio problema: il problema era che la mia libreria C ++ utilizzava una versione precedente della libreria C. Questa vecchia versione mancava il quarto argomento. Di conseguenza, il quarto argomento ovviamente non è mai stato modificato.

Mi vergogno un po 'adesso che ho capito che questo era il problema. Tuttavia, sono stato fuorviato dal fatto che il mio codice si stava compilando bene. Ciò era dovuto al fatto che la libreria C ++ si compilava con la versione corretta della libreria C, ma in fase di runtime utilizzava la vecchia versione collegata staticamente con un'altra libreria che stavo usando.

C++ Lib (M) ---> dyn C++ lib (N) ---> C lib (P) v.1.0
     |
     ------> C lib (P) v.1.1

(N) è una libreria dinamica collegata staticamente con (P) versione 1.0. Il compilatore ha accettato la chiamata da (M) alla funzione con 4 argomenti perché ho collegato contro (P) versione 1.1, ma in fase di esecuzione ha usato la vecchia versione di (P).

Sentiti libero di modificare questa risposta o la domanda o di chiedermi di farlo.

Altri suggerimenti

Sembra una differenza tra il modo in cui la tua libreria C e il compilatore C ++ hanno a che fare con long longs . La mia ipotesi è che la libreria C sia probabilmente pre standard C89 e in realtà tratta il long long a 64 bit come un long a 32 bit. La tua libreria C ++ la sta gestendo correttamente e posizionando 64 bit nello stack di chiamate e quindi corrompendo y e z. Forse prova a chiamare la funzione tramite * int A (unsigned int a, unsigned long b, unsigned int * y, unsigned char z) , e vedi cosa ottieni.

Solo un pensiero.

Questa è una di quelle domande in cui non c'è ovviamente nulla di sbagliato in ciò che hai descritto, eppure le cose non funzionano come ti aspetti.

Penso che dovresti modificare il tuo post per fornire molte più informazioni al fine di ottenere alcune risposte sensate. In particolare, cominciamo con: -

  • Per quale piattaforma è questo codice: Windows, Linux, qualcosa di incorporato o ...?
  • Che compilatore è il C libreria statica costruita con?
  • Cosa il compilatore è la libreria dinamica C ++ costruito con?
  • Che compilatore è il C che può chiamare correttamente il libreria costruita con?
  • Hai un debugger a livello di sorgente? Se è così, puoi passi in il codice C dal C ++.

A meno che non ti sbagli su A che modifica sempre i dati indicati da Z, l'unica causa probabile del tuo problema è l'incompatibilità tra le convenzioni di passaggio dei parametri. Il "lungo lungo" Il problema potrebbe suggerire che le cose non sono come sembrano.

Come ultima risorsa, potresti confrontare il codice di chiamata C ++ disassemblato (che dici che fallisce) e il codice di chiamata C (che dici che ha successo), oppure scorrere le istruzioni della CPU con il debugger (sì, davvero - tu ' imparerò una buona abilità e risolverò il problema)

Per quanto ne so, da molto tempo non fa parte del C ++ standard, forse questa è la fonte del tuo problema.

Non lo so. Prova a eseguire il debug in A e guarda cosa succede (avviso codice assembly!)

Forse puoi avvolgere la funzione originale in una libreria C che chiami dalla tua libreria C ++?

Sulla base dei tuoi punti 2 e 3, sembra che potrebbe funzionare.

In caso contrario, ti offre un altro punto di debug per trovare altri indizi: vedi in quale delle tue librerie viene visualizzato l'errore per primo e controlla perché 2 e 3 funzionano, ma non funziona: qual è il minimo differenza?

Potresti anche provare a esaminare lo stack impostato dalla tua chiamata di funzione in ogni caso per verificare se la differenza è presente, considerando diverse convenzioni di chiamata.

Passaggio 1: confronta i puntatori y e z passati dal lato C ++ con quelli ricevuti dalla funzione C.

P.S. Non voglio sembrare ovvio, ma sto solo ricontrollando qui. Suppongo che quando dici che z viene modificato bene quando viene chiamato da un binario C, intendi che i dati su cui sta puntando z vengono modificati bene. I puntatori ye z vengono passati per valore, quindi non è possibile modificarli.

Un'altra ipotesi selvaggia: sei sicuro di collegarti all'istanza corretta della funzione nella tua libreria C? Potrebbe essere che ci siano molte di queste funzioni disponibili nelle tue librerie? In C il linker non si preoccupa del tipo restituito o dell'elenco dei parametri quando decide come risolvere una funzione - solo il nome è importante. Quindi, se hai più funzioni con lo stesso nome ...

È possibile verificare a livello di codice l'identità della funzione. Crea una libreria C che chiama la tua funzione A con alcuni parametri di test e che funzioni bene e che stampa il puntatore alla funzione A. Collega la libreria all'app C ++. Quindi stampa il puntatore sulla funzione A originale come visto dal codice C ++ e confronta il puntatore con quello visto dalla tua libreria C quando viene invocato nello stesso processo.

Ancora una volta, ovvio, ma chi lo sa ... Sei sicuro che la funzione C che stai invocando sia senza stato, il che significa che il suo output dipende solo dai suoi input? Se la funzione non è stateless, è possibile che il " nascosto " state è responsabile del diverso comportamento (non modifica dei dati indicati da z ) della funzione quando viene invocato dall'app C ++.

Nel tuo programma C ++, il prototipo è dichiarato con extern & C; quot & ?

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top