Question

J'ai une fonction C dans une bibliothèque statique, appelons-la A, avec l'interface suivante:

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

Cette fonction changera la valeur de y an z (c’est certain). Je l'utilise depuis une bibliothèque C ++ dynamique, en utilisant extern "C".

Maintenant, voici ce qui m’a accordé:

  • y est correctement défini, z n'est pas modifié. Ce que je veux dire exactement, c’est que si les deux sont initialisés avec une valeur (pointée) de 666, la valeur pointée par y aura changé après l’appel mais pas la valeur pointée par z (encore 666).
  • quand elle est appelée à partir d’un binaire C, cette fonction fonctionne de manière transparente pointé par z est modifié).
  • si je crée une bibliothèque fictive C avec une fonction ayant le même prototype et que je l'utilise à partir de ma bibliothèque dynamique C ++, cela fonctionne très bien. Si je réutilise les mêmes variables pour appeler A (..), j'obtiens le même résultat qu'auparavant, z n'est pas modifié.

Je pense que les points ci-dessus montrent que ce n’est pas une erreur stupide avec la déclaration de mes variables.

Je suis clairement coincé et je ne peux pas changer la bibliothèque C. Avez-vous une idée de ce que peut être le problème? Je pensais à un problème sur l'interface C / C ++, par exemple la façon dont char * est interprété.

Edit: J'ai finalement découvert quel était le problème. Voir ci-dessous ma réponse.

Était-ce utile?

La solution 9

Tout d’abord, je suis très reconnaissant à tous pour votre aide. Grâce aux nombreuses idées et indices que vous m'avez donnés, j'ai enfin pu résoudre ce problème. Vos conseils m'ont aidé à remettre en question ce que je tenais pour acquis.

Réponse courte à mon problème: le problème était que ma bibliothèque C ++ utilisait une ancienne version de la bibliothèque C. Cette ancienne version a manqué le 4ème argument. En conséquence, le 4ème argument n'a évidemment jamais été modifié.

J'ai un peu honte maintenant que j'ai compris que c'était le problème. Cependant, j'ai été trompé par le fait que mon code compilait bien. Cela était dû au fait que la bibliothèque C ++ avait été compilée avec la version correcte de la bibliothèque C, mais qu'au moment de l'exécution, elle utilisait l'ancienne version liée de manière statique à une autre bibliothèque que j'utilisais.

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

(N) est une bibliothèque dynamique liée statiquement à (P) version 1.0. Le compilateur a accepté l'appel de (M) à la fonction avec 4 arguments, car j'ai lié la version 1.1 à (P), mais au moment de l'exécution, il utilisait l'ancienne version de (P).

N'hésitez pas à modifier cette réponse ou cette question ou à me demander de le faire.

Autres conseils

Cela ressemble à une différence entre la façon dont votre bibliothèque C et le compilateur C ++ traitent long long . Mon hypothèse est que la bibliothèque C est probablement antérieure à la norme C89 et traite en fait la longue longue de 64 bits comme une longue de 32 bits. Votre bibliothèque C ++ le gère correctement et place 64 bits sur la pile d'appels, corrompant ainsi y et z. Essayez peut-être d'appeler la fonction via * int A (unsigned int a, unsigned long b, unsigned int * y, unsigned char z) , et voyez ce que vous obtenez.

Juste une pensée.

C’est l’une de ces questions pour lesquelles il n’ya rien de mal à ce que vous décrivez, alors que tout ne fonctionne pas comme prévu.

Je pense que vous devriez modifier votre message pour fournir davantage d'informations afin d'obtenir des réponses judicieuses. En particulier, commençons par: -

  • À quelle plate-forme appartient ce code: Windows, Linux, quelque chose d'embarqué ou ...?
  • Quel compilateur est le C bibliothèque statique construite avec?
  • Quoi le compilateur est la bibliothèque dynamique C ++ construit avec?
  • Quel compilateur est le C qui peut appeler le bibliothèque construite avec?
  • Avez-vous un débogueur de niveau source? Si oui, peut vous entrez dans le code C à partir du C ++.

À moins que vous ne vous trompiez sur A en modifiant constamment les données pointées par Z, la seule cause probable de votre problème est une incompatibilité entre les conventions de passage de paramètres. Le " long long " question peut être un indice que les choses ne sont pas comme elles semblent.

En dernier recours, vous pouvez comparer le code d’appel C ++ désassemblé (dont vous dites qu’il échoue) et le code d’appel C (dont vous dites qu’il réussit), ou parcourir les instructions de la CPU avec le débogueur (oui, vraiment - vous ' ll apprendra une bonne technique et résoudra le problème)

Pour autant que je sache, long long ne fait pas partie du C ++ standard, c'est peut-être la source de votre problème.

ne sais pas. Essayez de déboguer dans A et de voir ce qui se passe (alerte code assembleur!)

Peut-être pouvez-vous envelopper la fonction d'origine dans une bibliothèque C que vous appelez à partir de votre bibliothèque C ++?

Sur la base de vos points 2 et 3, il semble que cela puisse fonctionner.

Si ce n'est pas le cas, cela vous donnera un autre point de débogage pour trouver plus d'indices. Découvrez dans quelle bibliothèque l'échec apparaît en premier, et vérifiez pourquoi 2 et 3 fonctionnent, mais cela ne fonctionne pas - quel est le minimum différence?

Vous pouvez également essayer d'examiner la pile configurée par votre appel de fonction dans chaque cas pour vérifier si la différence est présente - en tenant compte de conventions d'appel différentes.

Étape 1: comparez les pointeurs y et z passés du côté C ++ avec ceux reçus par la fonction C.

P.S. Je ne veux pas paraître évident, mais juste vérifier ici. Je suppose que lorsque vous dites que z est bien modifié lorsqu'il est appelé à partir d'un binaire C, vous voulez dire que les données pointées par z sont modifiées correctement. Les pointeurs y et z sont eux-mêmes passés par valeur, vous ne pouvez donc pas les changer.

Autre hypothèse fictive: êtes-vous sûr de lier la bonne instance de la fonction dans votre bibliothèque C? Se pourrait-il que plusieurs de ces fonctions soient disponibles dans vos bibliothèques? En C, l’éditeur de liens ne se soucie pas du type de retour ni de la liste de paramètres pour décider comment résoudre une fonction - seul le nom est important. Donc, si vous avez plusieurs fonctions portant le même nom ...

Vous pouvez vérifier par programme l'identité de la fonction. Créez une bibliothèque C qui appelle votre fonction A avec quelques paramètres de test, fonctionne correctement et affiche le pointeur sur la fonction A. Liez la bibliothèque à votre application C ++. Imprimez ensuite le pointeur sur la fonction A d'origine telle que vue dans le code C ++ et comparez-le à celui vu par votre bibliothèque C lorsqu'il est appelé dans le même processus.

Encore une fois, une évidence, mais qui sait ... Etes-vous sûr que la fonction C que vous appelez est sans état, ce qui signifie que sa sortie ne dépend que de ses entrées? Si la fonction n’est pas sans état, il se peut que le caractère "masqué" state est responsable du comportement différent (ne pas modifier les données pointées par z ) de la fonction lorsqu'il est appelé depuis votre application C ++.

Dans votre programme C ++, le prototype est-il déclaré avec extern "" C "?

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top