HarryZhu

# 案例

## Python

``````def tally(s):
total = 0
for elm in s:
total += elm

## C

``````#include <stddef.h>

double tally(double *s, size_t n) {
double total = 0;
for (size_t i = 0; i < n; i++) {
total += s[i];
}
}``````

## Cython

``````#include <stdio.h>
#include "Python.h"
#include "tally.h"

static PyObject *tally_(PyObject *self, PyObject *args) {
PyObject *buf;
if (!PyArg_ParseTuple(args, "O", &buf)) {
return NULL;
}

Py_buffer view;
int buf_flags = PyBUF_ANY_CONTIGUOUS | PyBUF_FORMAT;
if (PyObject_GetBuffer(buf, &view, buf_flags) == -1) {
return NULL;
}

if (strcmp(view.format,"d") != 0) {
PyErr_SetString(PyExc_TypeError, "we only take floats :(");
PyBuffer_Release(&view);
return NULL;
}

double result = tally(view.buf, view.shape[0]);
PyBuffer_Release(&view);
return Py_BuildValue("d", result);
}

static PyMethodDef MethodTable[] = {
{"tally", &tally_, METH_VARARGS, "Compute the sum of an array"},
{ NULL, NULL, 0, NULL}
};

static struct PyModuleDef tally_module = {
.m_name = "tally_",
.m_size = -1,
.m_methods = MethodTable
};

PyMODINIT_FUNC PyInit_tally_(void) {
return PyModule_Create(&tally_module);
}``````

## R

R的过程非常相似，但是更加简洁:

``````#include <R.h>
#include <Rinternals.h>
#include "tally.h"

SEXP tally_(SEXP x_) {
double *x = REAL(x_);
int n = length(x_);

SEXP out = PROTECT(allocVector(REALSXP, 1));
REAL(out)[0] = tally(x, n);
UNPROTECT(1);

return out;
}

static R_CallMethodDef callMethods[] = {
{"tally_", (DL_FUNC)&tally_, 1},
{NULL, NULL, 0}
};

void R_init_tallyR(DllInfo *info) {
R_registerRoutines(info, NULL, callMethods, NULL, NULL);
}``````

# 总结

• 如果你打算在两者之间共享函数就不要依赖宿主语言的api(R或Python)代码。

• 使用错误码来传递异常提示，不要直接调用退出或者在宿主语言里面才处理异常。

• 最好用宿主语言负责内存分配和重分配,这意味着你的C/C++代码应该要略过预先分配的内存和输出过程。

• 相信编译器,你也应该重视编译器的错误和警告。如果代码在编译时有警告那代码就不算写完。

2.2k 声望
2.1k 粉丝
0 条评论