[c++]从完全不会到似懂非懂

Posted 笨喵敲代码

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[c++]从完全不会到似懂非懂相关的知识,希望对你有一定的参考价值。

1. 指针

1.1 指针常量

使用int * const p = &a;的模式,指针常量是常量,所以p对应的常量为a的地址,因此a可变,但地址不可变。

1.2 常量指针

使用const int *p = &a的模式,其实这里和const无关,p只是个指针,该指针的类型是const int类型,因此p可以修改指针指向其他的const int类型,但无法修改指向的内存中的值(可以通过其他的引用来修改,const可以指向非const,非const不可指向const)。

2. 结构体

结构体const

为了防止在函数中修改原本的结构体内容,因此需要将函数的形参声明为const类型,即const struct student *p,也就是p指针的类型是const struct student *类型,因为无法修改结构体。联想到Android开发中的局部变量final修饰,表示以后对该变量仅有只读操作,强调只读性。

使用 ctypes 将数组从 Python 传递到 C++,无法完全处理它

【中文标题】使用 ctypes 将数组从 Python 传递到 C++,无法完全处理它【英文标题】:Passing array from Python to C++ using ctypes, unable to process it entirely 【发布时间】:2019-03-12 14:51:18 【问题描述】:

按照我在tutorial 中找到的方法,我编写了以下代码来使用ctypes 库修改我的自定义python 类Pointwrap_function 只是一个便于使用的小帮手,因为这是来自更大项目的 MWE。

在python方面:

import ctypes
import numpy as np 
libc = ctypes.WinDLL(r'C:\Path\lib.dll')
 
def wrap_function(lib, funcname, restype, argtypes): 
    func = lib.__getattr__(funcname) 
    func.restype = restype 
    func.argtypes = argtypes 
    return func 
 
class Point(ctypes.Structure): 
    _fields_ = [('x', ctypes.c_int), ('xdata', ctypes.c_void_p)]
     
list_of_points = []                                #unused for now 
xdata = np.zeros((40000,), dtype=np.double)
a = Point(1,xdata.ctypes.data) 
b = Point(3,xdata.ctypes.data) 

change_data_for_point = wrap_function(libc,'change_data_for_point', None, [ctypes.POINTER(Point)])
change_data_for_point(a)

在 C 端:

---header: 

const int N = 40000;
typedef struct 
    double x; 
    double xdata[N];
 Point;

extern "C" LIB_API void change_data_for_point(Point* p);


---source:

void change_data_for_point(Point* p) 
    p->x++; 
    for (int i = 0; i < 40000; i++) 
        p->xdata[i] = 2.0*i;
        if (i % 1000 == 0) printf("xdata at index %d is %f\n", i, p->xdata[i]);
    

在 Windows 7 cmd 中执行 python 文件时,它会打印以下输出:

xdata at index 0 is 0.000000
xdata at index 1000 is 2000.000000
 // ... some more ... 
xdata at index 17000 is 34000.000000
xdata at index 18000 is 36000.000000
Traceback (most recent call last):
   File "test.py", line 40, in <module>

为什么它会停在 18.000 ?我试了几次,有时循环达到 19 或 20k,但它从来没有比这更高。它与C端的数组初始化有关吗?我是不是弄乱了python端的参数传递?


额外问题:如何使用 ctypes 将这些点的列表传递给 C 端?

【问题讨论】:

try-catch-block包围python中的关键行现在让我打印exception: access violation writing 0x0000000006F60000,所以我认为我很可能在C端搞砸了。 Point 定义在 CPython 不匹配 ( xdata). 【参考方案1】:

虽然 NumPy 增加了额外的复杂性级别,但每条信息都可以在 [Python 3]: ctypes - A foreign function library for Python 上找到。

(主要)问题是 Point 结构在 CPython 中的定义不同。 另外,函数需要Point*,所以必须使用byref(没有它也可以工作,我不知道这是否是未定义的行为的快乐案例,或者 ctypes 默默地这样做 - 由于 argtypes)。

我已经修改了你的代码以便工作。

dll.c

#include <stdio.h>

#if defined(_WIN32)
#  define DLL_EXPORT __declspec(dllexport)
#else
#  define DLL_EXPORT
#endif


const int N = 40000;

typedef struct 
    double x;
    double xdata[N];
 Point;


#if defined(__cplusplus)
extern "C" 
#endif

    DLL_EXPORT void change_data_for_point(Point *p);

#if defined(__cplusplus)

#endif


void change_data_for_point(Point *p) 
    p->x++; 
    for (int i = 0; i < 40000; i++) 
        p->xdata[i] = 2.0 * i;
        if (i % 10000 == 9999)
            printf("xdata at index %d is %f\n", i, p->xdata[i]);
    

code.py

#!/usr/bin/env python3

import sys
import ctypes
import numpy as np


DLL_NAME = "./dll.dll"

xdata_dim = 40000  # !!! Must match N (from C) !!!
DoubleArr = ctypes.c_double * xdata_dim

class Point(ctypes.Structure): 
    _fields_ = [
        ("x", ctypes.c_int),
        ("xdata", DoubleArr),
    ]


def wrap_function(lib, funcname, restype, argtypes):
    func = lib.__getattr__(funcname)
    func.restype = restype
    func.argtypes = argtypes
    return func


def main():
    dll = ctypes.CDLL(DLL_NAME)
    #xdata_dim = ctypes.c_int.in_dll(dll, "N")

    xdata = np.zeros((xdata_dim,), dtype=np.double)
    a = Point(1, DoubleArr.from_address(xdata.ctypes.data))
    b = Point(3, DoubleArr.from_address(xdata.ctypes.data))
    change_data_for_point = wrap_function(dll,"change_data_for_point", None, [ctypes.POINTER(Point)])
    change_data_for_point(ctypes.byref(a))
    print(a.xdata[30000])


if __name__ == "__main__":
    print("Python :s on :s\n".format(sys.version, sys.platform))
    main()

输出

[cfati@CFATI-5510-0:e:\Work\Dev\***\q055124400]> sopr.bat
*** Set shorter prompt to better fit when pasted in *** (or other) pages ***

[prompt]> "c:\Install\x86\Microsoft\Visual Studio Community\2015\vc\vcvarsall.bat" x64

[prompt]> dir /b
code.py
dll.c

[prompt]> cl /nologo /DDLL /MD /Tp dll.c  /link /NOLOGO /DLL /OUT:dll.dll
dll.c
   Creating library dll.lib and object dll.exp

[prompt]> dir /b
code.py
dll.c
dll.dll
dll.exp
dll.lib
dll.obj

[prompt]> "e:\Work\Dev\VEnvs\py_064_03.06.08_test0\Scripts\python.exe" code.py
Python 3.6.8 (tags/v3.6.8:3c6b436a57, Dec 24 2018, 00:16:47) [MSC v.1916 64 bit (AMD64)] on win32

xdata at index 9999 is 19998.000000
xdata at index 19999 is 39998.000000
xdata at index 29999 is 59998.000000
xdata at index 39999 is 79998.000000
60000.0

@EDIT0

如果你想处理 Point 的列表,你可以使用数组。比如:

PointArr = Point * len(list_of_points)
point_arr = PointArr(*list_od_points)

【讨论】:

非常感谢!这真的很有帮助:) 如果我想将一个点列表传递给 C 端来编辑它们,我会怎么做?我已经尝试在 python 端嵌套结构,但在执行时出现访问冲突错误! 但是您已经在编辑它们了。 xdata 数组中的值是从 C. 设置的 哈哈,是的,我知道!也许我没有足够清楚地表达我的意图 - 比如说,我在 Python 端有一个 n 点对象的列表。现在我想将该列表传递给一个函数(整个列表,而不是单独的所有 n 点 - 它们必须同时出现在 C 端)。这个函数,在 C 端,应该遍历列表并编辑来自这 n 个点中的每一个的数据。我想过做类似class pointList(ctypes.Structure): _fields_ = [('1',point), ('2',point), ... ('n',point),] 之类的事情,然后将它与数字 n 一起传递给一个函数。 然后使用点数组。你的建议是不可能的(至少不是那种形式)。检查***.com/questions/55103298/… - 您必须执行类似于 CharArr 的操作(位于 main 末尾的某处)。 谢谢你!我通过分别传递几个点找到了一种解决方法,但将它们存储在 C 端的 std::vector&lt;Point*&gt; 中。感谢您的帮助!

以上是关于[c++]从完全不会到似懂非懂的主要内容,如果未能解决你的问题,请参考以下文章

IO模型之完全懵逼到似懂非懂

使用 ctypes 将数组从 Python 传递到 C++,无法完全处理它

返回后指针不会从函数返回到它的引用(保持为空)C++

从 C# 调用 C++ 代码而不创建 dll?

将弱 ISR 处理程序从 Assembly 覆盖到 C++ 不会编译任何代码

从 c# 调用 C++ 代码