首页 > 解决方案 > 在 Python 中使用 ctypes.CDLL 调用 ac 函数时,函数总是将 0 作为参数传递

问题描述

我试图调用的 c 函数:

#include <stdio.h>    
#include <stdlib.h>    
  
int main(int argc, char *argv[]){       
    long long int n = atoll(argv[1]);    
    printf("main(%lld)\n", n);    
    int m = 0;         
    while (n > 1) {           
        m++;                  
        if (n % 2 == 0) {   // even    
            printf("%lld = %lld/2 \n", n/2, n);    
            n = n/2;    
        }    
        else {    
            printf("%lld = 3*%lld+1 \n", 3*n+1, n);    
            n = 3*n + 1;    
        }    
    }        
    printf("Collatz(%lld) is '%d'\n", n,m);    
    return m;    
}    

我的 python 代码尝试使用参数 4 调用它

from ctypes import *    
import os, sys                                                                    
                                                                                    
print("you typed:", sys.argv[1])                                                  
                                                                                    
filename = sys.argv[1].split(".")[0]                                              
                                                                                    
os.system(f"gcc -c -fPIC {filename}.c -o {filename}.o && gcc {filename}.o " \     
           f"-shared -o {filename}.so")                                           
       
soFile = CDLL(os.getcwd() + "/" + filename + ".so")    
       

soFile.main(4)       # <----------

在 vim 中,我运行以下命令:

:!python test.py "collatz-loop"                                                
you typed: collatz-loop
main(0)
Collatz(0) is '0'

注意输出如何为 0。即使我将参数更改为 4 以外的值,输出始终为 0。

如果我尝试更改soFile.main(4)为具有两个参数的东西,例如soFile.main(2, 4),我得到

:!python test.py "collatz-loop"

shell returned 139

为什么会发生这种情况,我该如何解决?

标签: pythonc++cctypesneovim

解决方案


评论线程的 TLDR:您应该将其拆分为 2 个函数,main并且collatz( int collatz(long long n)) 并使 main 只传递atoll(argv[1])给 collat​​z,因此您可以将其作为可执行文件正常运行,也可以从 python 脚本文件作为共享库运行。您还需要将 ctypes 中的 argtype 设置为 long long(我认为它默认为 int)。

C:

#include <stdio.h>
#include <stdlib.h>

int collatz(long long n){
    int m = 0;
    while (n > 1) {
        m++;
        if (n % 2 == 0) {   // even
            printf("%lld = %lld/2 \n", n/2, n);
            n = n/2;
        }
        else {
            printf("%lld = 3*%lld+1 \n", 3*n+1, n);
            n = 3*n + 1;
        }
    }
    printf("Collatz(%lld) is '%d'\n", n,m);
    return m;
}

int main(int argc, char *argv[]){
    long long int n = atoll(argv[1]);
    printf("main(%lld)\n", n);
    collatz(n);
}

Python:

from ctypes import *
import os, sys

print("you typed:", sys.argv[1])

filename = sys.argv[1].split(".")[0]

os.system(f"gcc -c -fPIC {filename}.c -o {filename}.o && gcc {filename}.o " \
           f"-shared -o {filename}.so")

soFile = CDLL(os.getcwd() + "/" + filename + ".so")


soFile.collatz.argtypes = [c_longlong]
soFile.collatz(4)

注意:与此问题没有直接关系,但您应该检查以确保argc > 2在您的 C 代码中避免在没有传递参数的情况下越界读取。


推荐阅读