0
votes

Deux noms pour la même fonction

J'ai besoin de deux instances de la même fonction (pas seulement d'un alias). Une chose qui fonctionne vraiment est

writedata = parallel.writedata
writedata.argtypes = [devpointer, POINTER(c_ubyte), c_int]

writestring = parallel.writestring
writestring.argtypes = [devpointer, c_char_p, c_int]

C'est un peu idiot, car le second ne fait que passer des paramètres au premier. Alors j'ai essayé d'être "intelligent" et de faire un pointeur

void writedata(union chip *tempchip, unsigned char *datapos, int datanum)
{
   blahblah
}

void (* writestring)(union chip *, unsigned char *, int) = writedata;

qui lors de l'utilisation renvoie une erreur de segmentation. Pourquoi la deuxième méthode ne fonctionne-t-elle pas?

EDIT: ctypes deux fonctions de Python via ctypes :

void writedata(union chip *tempchip, unsigned char *datapos, int datanum)
{
   blahblah
}

void writestring(union chip *tempchip, unsigned char *datapos, int datanum)
{
   writedata(tempchip, datapos, datanum);
}

parce que je veux fournir à la fois la string s et le byte array s comme deuxième argument.


18 commentaires

semble correct, pouvez-vous donner un exemple complet?


ne peut pas se reproduire . poster un exemple minimal reproductible .


L'appelez-vous à partir d'un fichier séparé? Il doit être déclaré de manière cohérente avec la définition, c'est-à-dire comme un pointeur de fonction et non comme une fonction.


ctypes deux fonctions de Python via ctypes .


@Pygmalion C'est le problème. ctypes essaie de l'appeler en tant que fonction. Il doit l'appeler comme un pointeur vers une fonction, c'est-à-dire qu'il doit d'abord charger la valeur du pointeur, puis l'appeler. writestring n'est pas vraiment un alias pour writedata . C'est un pointeur qui le désigne. La syntaxe C est très flexible à ce sujet, elle peut donc sembler être un alias, mais ce n'est pas le cas. writestring a un stockage associé, pour le pointeur.


@TomKarzes OK alors est-il possible de créer un alias, appelable de l'extérieur, mais sans passage ridicule d'arguments?


@Pygmalion Ce que vous voulez vraiment, c'est que votre fichier objet définisse deux symboles pour la même fonction. C'est un désir raisonnable, mais je ne connais pas de moyen de le faire. Cela pourrait être possible en manipulant le fichier objet d'une manière ou d'une autre, mais je ne pense pas que cela puisse être fait directement à partir de C.


@TomKarzes Donc ma solution idiote est juste la meilleure que je puisse réaliser et je devrais en être satisfaite?


@Pygmalion C'est certainement le plus simple et le plus portable. Essayer d'aliaser les symboles dans le fichier objet est au mieux incertain.


@Pygmalion "simple et pragmatique" c'est pas idiot.


@TomKarzes IIRC, K&R avait un mot-clé pour cela (entrée?)


@wildplasser Huh, c'est intéressant. Je ne pense pas qu'il ait jamais été systématiquement soutenu. J'ai trouvé ceci qui en discute un peu. Mais oui, c'est exactement ce que recherche OP.


Je ne l'ai jamais utilisé non plus. La communication avec l'éditeur de liens était plutôt rurale, à l'époque. (traits de soulignement, etc.)


@Pygmalion Une autre possibilité est de faire #define writestring writedata dans un fichier d'en-tête, de sorte qu'elles finissent par se développer en données writedata . Cela vous permettrait d'utiliser le nom approprié dans votre code source tout en n'ayant qu'une seule fonction. Il n'apparaîtra tout simplement pas dans la table des symboles.


@TomKarzes J'ai essayé la méthode de define , mais ctypes n'a pas pu trouver de writestring . Il semble que le compilateur C n'a pas créé d'instance de writestring car il n'a jamais été utilisé. Peut-être que le problème est que je n'utilise pas du tout de fichiers d'en-tête?


Pour clarifier, avez-vous une fonction en C, mais à partir de Python, vous voulez passer à la fois des chaînes d'octets (par exemple b'test' ) et des tableaux d'octets (par exemple (c_ubyte*8)(1,2,3) ). Cela semble être un problème XY que vous devez décrire plus en détail. Je demande à cause de cette autre question qui est la vôtre ...


J'ai rencontré ce problème et l'ai résolu avec quelques-unes des suggestions de réponses manquant OS, Version Python, shell, etc. Il y a des indicateurs qui ne fonctionnent que dans des endroits spécifiques, avec des restrictions du système d'exploitation sur lequel vous vous trouvez. Votre autre question suggère que c'est le problème auquel vous n'avez pas fourni les informations que Mark a demandées et auxquelles il devait répondre.


@MarkTolonen Vous avez bien posé la question. J'ai décrit mon problème aussi bien que possible, mais je suis ouvert aux suggestions pour l'améliorer.


3 Réponses :


0
votes

Deux instances de la même fonction: (je pense que l'OP voulait deux entry points , ou labels ou symbols , cependant)


inline static unsigned f0( unsigned aa, unsigned bb)
{
return aa %bb + bb %aa;
}

#if WANT_MAGIC /* not needed, anyway */
#define MAGIC  __attribute__ ((noinline)) 
#else
#define MAGIC  /**/
#endif

unsigned MAGIC f1( unsigned aa, unsigned bb)
{
return f0( aa, bb);
}

unsigned MAGIC f2( unsigned aa, unsigned bb)
{
return f0( aa, bb);
}

Vous pouvez rendre les fonctions f1 et f2 différentes: en acceptant différents types d'argument et en effectuant une conversion appropriée.


1 commentaires

Merci d'avoir répondu.



2
votes

Je pense qu'il existe une solution qui pourrait fonctionner pour vous. Il réalise l'effet que vous recherchiez, mais il le fait à partir de l'éditeur de liens plutôt que de votre source C.

Mon hypothèse est que vous créez une bibliothèque partagée à utiliser avec Python. Si cette hypothèse est correcte, vous pouvez effectuer les opérations suivantes.

Disons que votre bibliothèque partagée s'appelle libclib1.so , et que vous faites quelque chose comme ce qui suit pour la créer:

gcc -shared mysource.o @aliases.txt -o libclib1.so

Vous pouvez modifier cela pour ajouter un alias pour votre fonction comme suit:

-Xlinker -defsym=writestring=writedata

Cela créera un nouveau symbole, writestring , avec la même valeur que writedata .

Bien sûr, si vous en avez un certain nombre, cela peut être un problème en ligne de commande. Mais il y a aussi une solution à cela. Tout ce que vous avez à faire est de créer un fichier contenant toutes vos options d'alias. Par exemple, vous pouvez l'appeler aliases.txt . Cela ressemblerait à:

gcc -shared mysource.o -Xlinker -defsym=writestring=writedata -o libclib1.so

Le fichier peut contenir autant d'options que vous le souhaitez, chacune sur sa propre ligne. Ensuite, vous pouvez modifier votre commande de lien de bibliothèque partagée en:

gcc -shared mysource.o -o libclib1.so

Cela récupérera les options de aliases.txt , ajoutant tous vos alias nécessaires à libclib1.so .


1 commentaires

Juste testé et cela fonctionne! Et heureusement, je n'ai besoin que d'un seul alias.



2
votes

Je pense que vous voulez simplement transmettre des données différentes à une seule fonction, comme cette autre question que vous avez posée . La solution est d'utiliser un c_void_p côté Python pour accepter différents types de pointeurs. Le code C recevra le pointeur et le traitera comme un caractère unsigned char * .

Voici un exemple de DLL qui se concentre uniquement sur le problème:

test.c

01 02 03
01 02 03

test.py

from ctypes import *

dll = CDLL('./test')
_func = dll.func
_func.argtypes = c_void_p,c_size_t
_func.restype = None

def func(data):
    _func(data,len(data))

test1 = b'\x01\x02\x03'
test2 = (c_ubyte*3)(1,2,3)

func(test1)
func(test2)

Production:

#include <stdio.h>

__declspec(dllexport)
void func(unsigned char *datapos, size_t length)
{
    for(int i = 0; i < length; ++i)
        printf("%02hhx ",datapos[i]);
    printf("\n");
}


1 commentaires

Fantastique. Solution en fait très simple et logique, en contournant essentiellement la ctypes type de pointeur ctypes en spécifiant un pointeur générique. En ce moment ma solution préférée.