为什么这两个 C 函数在 Python 中使用 ctypes lib 调用时会生成不同的返回值?

Why these two C functions generate different return values when called in Python using ctypes lib?

提问人:AsheofMidgard 提问时间:10/28/2023 更新时间:10/29/2023 访问量:60

问:

在这里,我实现了两个 C 函数:

void testFunc1(int **a)
{
    int temp[4] = {1,2,3,4};
    *a = temp;
}

void testFunc2(int **a, int b)
{
    int temp[4] = {1,2,3,4};
    *a = temp;
}

如图所示,这两个函数应将 *a 的值更改为 temp[0] 的地址,因此可以通过指针 a 返回数组 temp。 b 不是使用的参数,我把它放在 testFunc2 中,因为我发现它可能会引起一些令人困惑的结果。然后我把这个代码文件编译成“./test.dll”。

但是,当我通过 ctypes lib 在 python 中调用这两个函数时:

from ctypes import *

testdll = CDLL("./test.dll")
testdll.testFunc1.argtypes = (POINTER(POINTER(c_int)),)
testdll.testFunc2.argtypes = (POINTER(POINTER(c_int)), c_int)

print("Test func 1:")
a = pointer(pointer(c_int(-1)))
print("  Before calling func:")
print(f"                      a={a}")
print(f"             a.contents={a.contents}")
print(f"    a.contents.contents={a.contents.contents}")
testdll.testFunc1(a)
print("  After calling func:")
print(f"                      a={a}")
print(f"             a.contents={a.contents}")
print(f"    a.contents.contents={a.contents.contents}")

print("Test func 2:")
a = pointer(pointer(c_int(-1)))
print("  Before calling func:")
print(f"                      a={a}")
print(f"             a.contents={a.contents}")
print(f"    a.contents.contents={a.contents.contents}")
testdll.testFunc2(a, c_int(4))
print("  After calling func:")
print(f"                      a={a}")
print(f"             a.contents={a.contents}")
print(f"    a.contents.contents={a.contents.contents}")

印刷品是这样的:

Test func 1:
  Before calling func:
                      a=<__main__.LP_LP_c_long object at 0x00000263EC1B2CD0>
             a.contents=<__main__.LP_c_long object at 0x00000263EC1B2D50>
    a.contents.contents=c_long(-1)
  After calling func:
                      a=<__main__.LP_LP_c_long object at 0x00000263EC1B2CD0>
             a.contents=<__main__.LP_c_long object at 0x00000263EC1B2DD0>
    a.contents.contents=c_long(1)
Test func 2:
  Before calling func:
                      a=<__main__.LP_LP_c_long object at 0x00000263EC1B2E50>
             a.contents=<__main__.LP_c_long object at 0x00000263EC1B2CD0>
    a.contents.contents=c_long(-1)
  After calling func:
                      a=<__main__.LP_LP_c_long object at 0x00000263EC1B2E50>
             a.contents=<__main__.LP_c_long object at 0x00000263EC1B2BD0>
    a.contents.contents=c_long(0)

它表明 testFunc2 似乎对值为“0”的整数表示 *。这是一个令人困惑的结果,因为 testFunc2 只在其参数列表中添加一个未使用的参数 b。为什么与 testFunc1 相比,它会生成不同的结果?

请参阅问题部分。我在那里提到了我的实验。

蟒蛇 C

评论

0赞 chux - Reinstate Monica 10/29/2023
“因此,数组温度可以通过指针 A 返回。” --> 否。返回时无效,因为无效。*atemp

答:

3赞 0___________ 10/28/2023 #1

当您分配对自动存储持续时间数组的引用(并因此在 Python 代码中取消引用它)时,这两个函数都会调用未定义的行为,这些数组在函数返回时将停止存在。

为什么这两个 C 函数在调用时会生成不同的返回值 在 Python 中使用 ctypes lib?

因为这是一种未定义的行为,你不能假设任何行为。

您需要使它们静态或动态分配它们:

void testFunc1(int **a)
{
    static int temp[4] = {1,2,3,4};
    *a = temp;
}

void testFunc1(int **a)
{
    int *temp = malloc(4 * sizeof(*temp));
    memcpy(temp, (int[]){1,2,3,4}, 4 * sizeof(*temp));
    *a = temp;
}

评论

0赞 chux - Reinstate Monica 10/29/2023
看起来你玩得很开心。memcpy(temp, (int[]){1,2,3,4}, 4 * sizeof(*temp));
0赞 AsheofMidgard 10/29/2023
非常感谢!简直不敢相信我忘记了这整件事。我想这些天我一定写了太多的 Python 而写的 C 太少了。