2wsx 发表于 2022-10-20 14:03:51

动态链接库

如何将c文件转换成DLL文件并在python中调用?

hrpzcf 发表于 2022-10-20 16:48:17

首先得把c中需要在外部调用的函数调用约定限制为__cdecl,然后把c编译为动态库,Linux下用gcc编译器,windows下用msvc或者mingw64的gcc都可以。Python代码中使用ctype加载动态库就可以调用了。具体两三句话说不清楚。

阿奇_o 发表于 2022-10-20 18:13:43

本帖最后由 阿奇_o 于 2022-10-20 18:19 编辑

我看你骨骼惊奇,直接给你以下秘籍:《C草巨蟒之DLL神掌》。。 能修炼到什么程度,就看你造化了,哈哈哈{:10_250:}

from ctypes import *

#----------以下四种加载DLL方式皆可—————————
# pDLL = WinDLL("./myTest.dll")
# pDll = windll.LoadLibrary("./myTest.dll")
# pDll = cdll.LoadLibrary("./myTest.dll")
pDll = CDLL("./TestDLL.dll")# 注意写全路径或相对路径


# 旧的cpp的例子:
# https://www.cnblogs.com/FHC1994/p/11421229.html
#调用动态链接库函数
# res = pDll.sum(1,2)# 旧的cpp加法的例子,返回 a+b
#打印返回结果
# print(res)


# 新例子(用gcc如何将c生成dll):
# https://www.bilibili.com/video/BV1E4411z7Ua/?vd_source=691572ece9556ac42935a92fe9cf7e76
# https://www.codementor.io/@a_hathon/building-and-using-dlls-in-c-d7rrd4caz

# msg = pDll.message()
# print(msg)    # 这样会多出两个11 (异常?)

pDll.message()# 这样即可,因为它本身就是用C的printf()打印到stdout

人造人 发表于 2022-10-20 18:20:44

$ ls
main.c
$ cat main.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>

void and_gate(char a, char b, char *c) {
    *c = a == '1' && b == '1' ? '1' : '0';
}

void or_gate(char a, char b, char *c) {
    *c = a == '0' && b == '0' ? '0' : '1';
}

#if 0
void xor_gate(char a, char b, char *c) {
    *c = a != b ? '1' : '0';
}
#else
void not_gate(char a, char *b) {
    *b = a == '1' ? '0' : '1';
}

void xor_gate(char a, char b, char *c) {
    char na, nb;
    char r0, r1;
    not_gate(a, &na);
    not_gate(b, &nb);
    and_gate(a, nb, &r0);
    and_gate(b, na, &r1);
    or_gate(r0, r1, c);
}
#endif

void half_adder_1bit(char a, char b, char *s, char *c) {
    xor_gate(a, b, s);
    and_gate(a, b, c);
}

void full_adder_1bit(char a, char b, char ci, char *s, char *co) {
    char temp_s, temp_c;
    half_adder_1bit(a, b, &temp_s, &temp_c);
    half_adder_1bit(temp_s, ci, s, &temp_c);
    or_gate(temp_c, temp_c, co);
}

void full_adder_2bit(const char *a, const char *b, char ci, char *s, char *co) {
    char temp_c;
    full_adder_1bit(a, b, ci, &s, &temp_c);
    full_adder_1bit(a, b, temp_c, &s, co);
}

void full_adder_4bit(const char *a, const char *b, char ci, char *s, char *co) {
    char temp_c;
    full_adder_2bit(&a, &b, ci, &s, &temp_c);
    full_adder_2bit(&a, &b, temp_c, &s, co);
}

void full_adder_8bit(const char *a, const char *b, char ci, char *s, char *co) {
    char temp_c;
    full_adder_4bit(&a, &b, ci, &s, &temp_c);
    full_adder_4bit(&a, &b, temp_c, &s, co);
}

void full_adder_16bit(const char *a, const char *b, char ci, char *s, char *co) {
    char temp_c;
    full_adder_8bit(&a, &b, ci, &s, &temp_c);
    full_adder_8bit(&a, &b, temp_c, &s, co);
}

void full_adder_32bit(const char *a, const char *b, char ci, char *s, char *co) {
    char temp_c;
    full_adder_16bit(&a, &b, ci, &s, &temp_c);
    full_adder_16bit(&a, &b, temp_c, &s, co);
}

void binary(char dest, const char *src) {
    memset(dest, '0', 32);
    size_t l = strlen(src);
    strncpy(dest + (32 - l), src, l);
}

void format(char *dest, const char src) {
    const char *p = NULL;
    for(size_t i = 0; i < 32; ++i) {
      if(src == '1') {p = &src; break;}
    }
    if(!p) p = src + 31;
    while(p != src + 32) *dest++ = *p++;
    *dest = '\0';
}

char *add(const char *a, const char *b) {
    char *a_ = malloc(32), *b_ = malloc(32);
    char *c = malloc(33);
    binary(a_, a); binary(b_, b);
    char ci = '0', co;
    full_adder_32bit(a_, b_, ci, c, &co);
    //format(c, c);
    c = '\0';
    free(a_); free(b_);
    return c;
}

void neg(char num) {
    for(size_t i = 0; i < 32; ++i) {
      xor_gate('1', num, &num);
    }
    char ci = '0', co;
    char one = "00000000000000000000000000000001";
    full_adder_32bit(num, one, ci, num, &co);
}

char *sub(const char *a, const char *b) {
    char *a_ = malloc(32), *b_ = malloc(32);
    char *c = malloc(33);
    binary(a_, a); binary(b_, b);
    neg(b_);
    char ci = '0', co;
    full_adder_32bit(a_, b_, ci, c, &co);
    //format(c, c);
    c = '\0';
    free(a_); free(b_);
    return c;
}

uint32_t number(const char n) {
    uint32_t rv = 0;
    const char *p = n;
    for(uint32_t mask = 0x80000000; mask; mask >>= 1) {
      if(*p++ == '1') rv |= mask;
    }
    return rv;
}

int main(void) {
    char a;
    char b;
    scanf("%32s", a);
    scanf("%32s", b);
    char *c0 = add(a, b);
    puts(c0);
    uint32_t cu0 = number(c0);
    printf("%u\n", cu0);
    if((int32_t)cu0 > 1) printf("大于1\n");
    free(c0);
    char *c1 = sub(a, b);
    puts(c1);
    uint32_t cu1 = number(c1);
    printf("%d\n", (int32_t)cu1);
    if((int32_t)cu1 < -1) printf("小于-1\n");
    free(c1);
    return 0;
}
$ gcc -g -Wall -shared -o main.dll main.c
$ ls
main.cmain.dll
$ file main.dll
main.dll: PE32+ executable (DLL) (console) x86-64, for MS Windows
$ python
Python 3.8.12 (default, Nov 23 2021, 20:18:25)
on cygwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import ctypes
>>> dll = ctypes.cdll.LoadLibrary('main.dll')
>>> dll
<CDLL 'main.dll', handle 509660000 at 0x6fffffec79d0>
>>> dll.main()
10110110
1001
00000000000000000000000010111111
191
大于1
00000000000000000000000010101101
173
0
>>> dll.add(b'10011100', b'100101')
1633360
>>> dll.add.restype = ctypes.c_char_p
>>> dll.add(b'10011100', b'100101')
b'00000000000000000000000011000001'
>>>
$

人造人 发表于 2022-10-20 18:24:42

学会百度,百度上面啥都有

2wsx 发表于 2022-10-20 18:34:03

hrpzcf 发表于 2022-10-20 16:48
首先得把c中需要在外部调用的函数调用约定限制为__cdecl,然后把c编译为动态库,Linux下用gcc编译器,windo ...

要是我给你一个c文件你能帮我转换一下吗?只要能在Python里调用就可以。

hrpzcf 发表于 2022-10-20 19:01:00

2wsx 发表于 2022-10-20 18:34
要是我给你一个c文件你能帮我转换一下吗?只要能在Python里调用就可以。

要是c项目不复杂等晚上有空可以帮你试试,楼上的大佬也行,他更专业

2wsx 发表于 2022-10-20 19:26:06

hrpzcf 发表于 2022-10-20 19:01
要是c项目不复杂等晚上有空可以帮你试试,楼上的大佬也行,他更专业

#include <stdio.h>
#include <stdlib.h>
#include <sys/io.h>

/*define read_pci_config*/
static unsigned char read_pci_config(unsigned int bus, unsigned int dev, unsigned int fun, unsigned int offset)
{
        unsigned int value;
        outl(0x80000000|(bus<<16)|(dev<<11)|(fun<<8)|offset,0xcf8);
        value=inb(0xcfc+(offset&3));
        return value;
}

/*define write_pci_config*/
void write_pci_config(unsigned int bus,unsigned int dev,unsigned int fun,unsigned int offset,unsigned int value)
{
        outl(0x80000000|(bus<<16)|(dev<<11)|(fun<<8)|offset,0xcf8);
        outb(value,0xcfc+(offset&3));
}

/*enumerate pci device by access CF8h CFCh port*/
int main()
{
        iopl(3);
        unsigned int offset;
        unsigned int bus;
        unsigned int dev;
        unsigned int fun;
        unsigned int data;
        unsigned char act;
        unsigned int count = 0;
        while(1)
        {
                printf("\nplease select functions:\n");
                printf("A:show all pci device\n");
                printf("B:show specific device configuration space\n");
                printf("0:quit\n");
                scanf("%c",&act);
                while(getchar()!='\n');
                switch(act)
                {
                        case 'A':
                        {
                                for(bus=0; bus<256; bus++)/*enumerate pci device*/
                                {
                                        for(dev=0; dev<32; dev++)
                                        {
                                                for(fun=0; fun<8; fun++)
                                                {
                                                        outl(0x80000000|(bus<<16)|(dev<<11)|(fun<<8),0xcf8);/* write address into address register*/
                                                        data=inl(0xcfc);/*obtain vendor ID from data register */
                                                        if(data!=0xffffffff)
                                                        {               
                                                                count++;
                                                                printf("bus#:%2x\t\t dev#:%2x\t fun#:%2x\t Device ID:%02x\t\t Vendor ID:%02x\n",bus,dev,fun,data>>16,data);

                                                        }
                                                }
                                        }

                                }
                                printf("Total devices: %d",count);
                                printf("\n");
                                break;
                        }
               
                        case 'B':
                        {
                                printf("please input bus# dev# fun# to show specific device configuration space:");
                                scanf("%2x\t%2x\t%2x", &bus,&dev,&fun);
                                outl(0x80000000|(bus<<16)|(dev<<11)|(fun<<8),0xcf8);
                                       data=inl(0xcfc);
                                while(1)
                                {
                                        if(data!=0xffffffff)
                                        {
                                                printf("\n00:");
                                                for(offset=0x00;offset<=0xff;offset++)
                                                {
                                                        printf("%02x ",read_pci_config(bus,dev,fun,offset));
                                                        if(((offset+1)%16==0)&&(offset<255))
                                                        {
                                                                printf("\n%02x:",(offset+1)/16*0x10);
                                                        }
                                                }
                                                break;
                                        }
                                        else
                                                continue;
                                }
                                printf("\n");
                                break;

                        }
                        case '0':
                                return;break;
                        default:
                                return;break;
                }
        }
        return 0;
}                       

hrpzcf 发表于 2022-10-20 20:07:20

2wsx 发表于 2022-10-20 19:26


啊这个是有入口函数的呀,编译成可执行文件直接执行不好吗

hrpzcf 发表于 2022-10-20 20:09:05

本帖最后由 hrpzcf 于 2022-10-20 20:11 编辑

2wsx 发表于 2022-10-20 19:26


调用环境为 Linux,因为 #include <sys/io.h> 在 Linux 下才有




hrpzcf 发表于 2022-10-20 20:16:56

hrpzcf 发表于 2022-10-20 20:09
调用环境为 Linux,因为 #include在 Linux 下才有

好吧我试了执行了一下出现 Segmentation fault 段错误,不知道是我执行环境的问题还是 c 代码有误,不知道你这个 c 是什么环境下用的?

2wsx 发表于 2022-10-21 08:21:54

hrpzcf 发表于 2022-10-20 20:16
好吧我试了执行了一下出现 Segmentation fault 段错误,不知道是我执行环境的问题还是 c 代码有误,不知 ...

在Linux下用GCC,我试过了可以正常运行。

2wsx 发表于 2022-10-21 08:22:41

2wsx 发表于 2022-10-21 08:21
在Linux下用GCC,我试过了可以正常运行。

我是有需求需要在Python下调用这个c代码

2wsx 发表于 2022-10-21 08:41:07

人造人 发表于 2022-10-20 18:20


大佬你这个代码怎么用啊,我没看懂{:10_266:}

人造人 发表于 2022-10-21 09:12:28

2wsx 发表于 2022-10-21 08:41
大佬你这个代码怎么用啊,我没看懂

代码都给你贴出来了,使用的指令也给你贴出来了
你哪里看不懂?
你得有基础才能玩这些东西呀


上面那个C代码是一个32位的全加器
用add函数包装了一下,让这个全加器更方便使用
上面的例子首先把这个C代码编译成dll
然后在python中调用
调用了C代码中的main函数和add函数

阿奇_o 发表于 2022-10-21 10:03:02

2wsx 发表于 2022-10-21 08:22
我是有需求需要在Python下调用这个c代码

可这C代码,你走通了吗,能用吗? 段错误,有没有?
其实要生成 动态库(共享库)也不难,就两句gcc命令(gcc -c ... ; gcc -shared ...),python调用也是两三句。
但c代码本身有bug,或环境不对等问题,就很难搞咯。

hrpzcf 发表于 2022-10-21 14:08:01

2wsx 发表于 2022-10-21 08:21
在Linux下用GCC,我试过了可以正常运行。

那你下载我的附件试看能运行吗

2wsx 发表于 2022-10-21 19:15:38

hrpzcf 发表于 2022-10-21 14:08
那你下载我的附件试看能运行吗

C:\Users\Drayce\AppData\Local\Programs\Python\Python39\python.exe C:/Users/Austin/Downloads/call/call/pycall.py
Traceback (most recent call last):
File "C:\Users\Austin\Downloads\call\call\pycall.py", line 6, in <module>
    inst = ctypes.CDLL("./libcall.so")
File "C:\Users\Drayce\AppData\Local\Programs\Python\Python39\lib\ctypes\__init__.py", line 374, in __init__
    self._handle = _dlopen(self._name, mode)
OSError: %1 不是有效的 Win32 应用程序。

Process finished with exit code 1



上面这些是运行结果
我用的是pycharm 好像运行不出来

hrpzcf 发表于 2022-10-21 19:17:34

2wsx 发表于 2022-10-21 19:15
C:%users\Drayce\AppData\Local\Programs\Python\Python39\python.exe C:/Users/Austin/Downloads/call/c ...

我不是说在Linux环境下运行了吗{:10_250:}

2wsx 发表于 2022-10-22 10:04:30

hrpzcf 发表于 2022-10-21 19:17
我不是说在Linux环境下运行了吗

因为头文件的原因所以在Windows下就一定运行不了是吗
因为我现在希望能在Windows下pycharm里运行
页: [1] 2
查看完整版本: 动态链接库