2010-10-08 22 views
1

Je travaille sur l'intégration de Python 2.6 dans une application C++ existante. Jusqu'à présent, j'ai les Bibliothèques liées et suis capable d'initialiser avec succès l'interpréteur Python et peut également transférer des données à Python. J'ai de la difficulté à le récupérer et j'espère que quelqu'un pourra me guider dans la bonne direction. Je travaille avec ceci:C++ et Python incorporé - Chaînes terminées NUL

Py_Initialize(); 

pModule = PyImport_ImportModule("cBuffers"); // This crashes after 1st call. 
pDict = PyModule_GetDict(pModule); 
pClass = PyDict_GetItemString(pDict, "rf_pdf"); 
pMeth = PyString_FromString("main"); 

if (PyCallable_Check(pClass) && PyClass_Check(pClass)) { 
    pInstance = PyInstance_New(pClass, NULL, NULL); 
    pOutput = PyObject_CallMethodObjArgs(pInstance, pMeth, pOpts, pInput, NULL); 
} 

if (pOutput != NULL) { 
    string pPdf = PyString_AsString(pOutput); 
    Py_DECREF(pOutput); 
} else { 
    PyErr_Print(); 
} 

// Cleanup 
Py_DECREF(pModule); 
Py_DECREF(pModule); // Has an extra reference, not positive why. 
Py_DECREF(pMeth); 
Py_DECREF(pInstance); 
Py_DECREF(pOpts); 
Py_DECREF(pInput); 

Py_Finalize(); 

pOpts et pInput sont tous deux générés en utilisant PyString_FromString plus tôt dans le code. Le problème que j'ai est que quand je tente de récupérer la sortie en utilisant PyString_AsString la valeur de retour est terminée NUL. Malheureusement, parce que je génère des documents PDF, les NUL ne sont pas seulement autorisés, ils sont presque garantis. Quelqu'un peut-il me dire comment je retourne les données de chaîne de Python en C++ sans finir à la première NUL qu'il rencontre? En complément, Ce code peut être appelé plusieurs fois dans le cadre d'un service d'arrière-plan qui crée des documents PDF à partir de données d'impression entrantes. La première fois que ce code est appelé, il fonctionne comme prévu. Les appels suivants échouent à la ligne indiquée juste après Py_Initialize(). De l'aide sur la façon de déterminer ce qui se passe là-bas serait également très appréciée. Merci à l'avance,

+0

NULL! = ASCII NUL. NULL est un pointeur vide, NUL est votre terminateur de chaîne. Mieux vaut ne pas confondre les deux! – LukeN

+0

@LukeN - Mise à jour, et merci de souligner que ces deux sont distincts, mais le problème est toujours que la chaîne que je retourne de Python les contient et j'ai besoin de savoir comment contourner. –

Répondre

1

Quelques points:

  • Ne pas utiliser des chaînes. Vous pourriez même être capable de les faire fonctionner ici avec quelques contorsions sur les fonctions * _StringAndSize() , mais ce ne sera pas ce que vous voulez . Vous devez stocker vos données dans une structure de données personnalisée (ou un tampon) qui est juste une séquence d'octets (avez-vous vraiment voulez que les clients effectuent des opérations de chaîne sur ces données en Python?). Si votre objet est vraiment un objet tampon, vous devez utiliser le Buffer API.

  • Votre module importé a un refcount de 2 parce qu'il est détenu dans sys.modules (pour l'efficacité pour la prochaine fois que vous essayez de l'importer). Jamais décréf références que vous ne possédez pas ou planter votre programme. La section Importing Modules de la documentation devrait vraiment couvrir ceci, mais ce n'est pas le cas.

  • Il est assez coûteux d'initialiser Python et de le démonter à chaque fois que vous effectuez ces opérations. Vous devriez essayer de réorganiser votre cas d'utilisation de sorte que vous pouvez appeler Py_Initialize seulement une fois lorsque votre application démarre (ou la première fois qu'il a besoin de Python), puis appelez seulement Py_Finalize lorsque votre application est définitivement fait avec Python, ou quand il se ferme . La plupart des fonctions C/API de Python peuvent renvoyer NULL pour indiquer qu'une exception a été levée et vous ne vérifiez presque jamais cette valeur. Si quelque chose échoue, vous allez commencer à vous écraser dans des endroits très étranges. Vous pouvez lire à ce sujet dans la section Exception Handling du manuel C/API.

+0

Nick - 1.Oui, je veux des opérations de chaînes en Python. 2. J'ai mis dans le Py_DECREF supplémentaire quand j'ai remarqué la référence supplémentaire, mais le code se bloque la deuxième fois par w/ou w/o it. 3 & 4. Je n'avais pas prévu de quitter l'instanciation ou la vérification d'erreur dans leurs états actuels, mais je voulais une preuve de concept avant d'aller beaucoup plus loin. –

+0

Nick - Également sur 1 - La bibliothèque en cours de génération de PDF s'attend à ce qu'un gestionnaire de fichiers y mette des données. J'utilise une instance StringIO en Python pour rester en dehors du disque, puis quand j'ai terminé la génération PDF, je récupère le contenu du tampon avec 'outfile.getvalue()'. Je suis tellement incapable de convertir ceci en bytearray - j'obtiens une erreur d'encodage. –

+0

Vous pouvez implémenter un très petit objet en C++ qui ressemblerait à un objet semblable à un fichier à Python (en implémentant simplement les méthodes de protocole appropriées) et l'utiliser à la place d'une instance StringIO. De cette façon, vous pouvez conserver les données en mémoire, sans avoir à vous soucier des octets nuls ou de la gestion des API, car il s'agit déjà d'une structure de données C++ native lorsque le client vous les renvoie. –