【问题标题】:When calling a c function using ctypes.CDLL in Python, the function always gets 0 passed along as argument在 Python 中使用 ctypes.CDLL 调用 c 函数时,函数总是将 0 作为参数传递
【发布时间】:2021-06-11 15:14:45
【问题描述】:

我试图调用的 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

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

  • 顺便说一下,我是 c 新手,但对 Java 非常熟悉。它们在句法上看起来非常相似。
  • 是的,我确实记得在运行 .py 文件之前保存/写入 python 和 c 文件。

【问题讨论】:

  • 除非我记错了什么,否则 argv[0] 不应该是第一个参数,而不是 argv[1]?
  • argv 没有传递给main,所以atoll(argv[1]) 不起作用。
  • 为什么会出现在main 中?您将它作为共享库加载,您不需要 main。只需将其更改为 int collatz(long long n) 或类似于 sig 的内容,它应该会被修复。
  • @SuperStormer 它是主要函数的原因是我还可以选择将 c 函数编译为可执行文件并执行例如./collatz-loop 4(顺便说一句,效果很好!)。您认为我可以在不更改 c-main-function 签名的情况下修复它吗?
  • 好的,然后将其拆分为 2 个函数,maincollatz 并使 main 只需将 atoll(argv[1]) 传递给 collatz

标签: python c++ c ctypes neovim


【解决方案1】:

评论线程的 TLDR: 您应该将其拆分为 2 个函数,maincollatz (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)

注意:与此问题没有直接关系,但您应该检查以确保 C 代码中的 argc &gt; 2 以避免在未传递任何参数时越界读取。

【讨论】:

    猜你喜欢
    • 2011-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多