【问题标题】:Two names for the same function同一个函数的两个名字
【发布时间】:2021-02-25 06:49:19
【问题描述】:

我需要相同函数的两个实例(不仅仅是别名)。绝对有效的一件事是

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);
}

这有点傻,因为第二个只是将参数传递给第一个。所以我尝试变得“聪明”并做一个指针

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

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

which on using 返回分段错误。为什么第二种方法不起作用?

编辑:我通过ctypesPython调用这两个函数:

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

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

因为我想同时提供 strings 和 byte arrays 作为第二个参数。

【问题讨论】:

  • 看起来不错,你能举个完整的例子吗?
  • 您是从单独的文件中调用它吗?它需要与定义保持一致,即作为函数指针,而不是函数。
  • 我通过ctypesPython调用这两个函数。
  • @Pygmalion 这就是问题所在。 ctypes 试图将其作为函数调用。它需要将它作为指向函数的指针来调用,即它需要首先加载指针的值,然后调用它。 writestring 并不是writedata 的别名。这是一个指向它的指针。 C 语法对此非常灵活,因此它可以显示 为别名,但事实并非如此。 writestring 已关联存储,用于指针。

标签: python c function pointers ctypes


【解决方案1】:

同一个函数的两个实例: (不过,我认为 OP 想要两个 entry points,或 labelssymbols


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);
}

您可以使 f1 和 f2 函数不同:接受不同的参数类型,并适当地进行转换。

【讨论】:

    【解决方案2】:

    我认为有一个可能适合您的解决方案。它实现了您所追求的效果,但它是通过链接器而不是您的 C 源代码实现的。

    我的假设是您正在构建一个与 Python 一起使用的共享库。如果该假设是正确的,那么您可以执行以下操作。

    假设您的共享库名为 libclib1.so,并且您正在执行以下操作来创建它:

    gcc -shared mysource.o -o libclib1.so
    

    您可以更改此项以为您的函数添加别名,如下所示:

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

    这将创建一个新符号writestring,其值与writedata 相同。

    当然,如果你有一堆这样的,在命令行上这样做可能是个问题。但也有解决方案。您需要做的就是创建一个包含所有别名选项的文件。例如,您可以将其命名为aliases.txt。它看起来像:

    -Xlinker -defsym=writestring=writedata
    

    该文件可以包含任意数量的选项,每个选项都在自己的行中。然后您可以将您的共享库链接命令更改为:

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

    这将从aliases.txt 中选择选项,将所有需要的别名添加到libclib1.so

    【讨论】:

    • 刚刚测试过,这行得通!幸运的是我只需要一个别名。
    【解决方案3】:

    我认为您只是想将不同的数据传递给单个函数,例如this other question you asked。解决方案是在 Python 端使用c_void_p 来接受不同类型的指针。 C 代码将接收指针并将其视为unsigned char *

    这里是一个只关注问题的示例 DLL:

    test.c

    #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");
    }
    

    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)
    

    输出:

    01 02 03
    01 02 03
    

    【讨论】:

    • 太棒了。实际上非常简单且合乎逻辑的解决方案,本质上是通过指定泛型指针来绕过ctypes 指针类型检查。目前我最喜欢的解决方案。
    猜你喜欢
    • 2021-11-07
    • 2014-06-06
    • 2014-03-31
    • 1970-01-01
    • 1970-01-01
    • 2011-02-08
    • 2022-08-19
    • 2017-03-12
    • 1970-01-01
    相关资源
    最近更新 更多