Search for examples on how to use the PyArg_ParseTupleAndKeywords
I found these questions:
They both use things like static char* kwlist[] = {"a", "b", NULL}
static int PyClass_init(PyClass* self, PyObject* args, PyObject* kwargs) {
char* path;
char* regex;
static char* kwlist[] = {"", "", NULL};
if( !PyArg_ParseTupleAndKeywords( args, kwargs, "s|s", kwlist, &path, ®ex ) ) {
return -1;
}
// other code ...
return 0;
}
Compiling this with language = "c++"
on setup.py
and build it with -std=c++11
throws this warning:
x86_64-linux-gnu-gcc -pthread -DNDEBUG -g -fwrapv -O0 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -fPIC -Isource -I/usr/include/python3.6m -c source/test.cpp -o build/temp.linux-x86_64-3.6/source/test.o -O0 -g -ggdb -std=c++11 -fstack-protector-all
source/test.cpp: In function ‘int PyClass_init(PyClass*, PyObject*, PyObject*)’:
source/test.cpp:41:42: warning: ISO C++ forbids converting a string constant to ‘char*’ [-Wwrite-strings]
static char* kwlist[] = {"a", "b", NULL};
^
Searching for this error I found this question Why is conversion from string constant to 'char*' valid in C but invalid in C++ taking about a fix, but applying the fix as static char* const kwlist[] = {"a", "b", NULL};
keeps/upgrades the warning introducing the error:
source/test.cpp:41:50: warning: ISO C++ forbids converting a string constant to ‘char*’ [-Wwrite-strings]
static char* const kwlist[] = {"a", "b", NULL};
^
source/test.cpp:41:50: warning: ISO C++ forbids converting a string constant to ‘char*’ [-Wwrite-strings]
source/test.cpp:43:89: error: invalid conversion from ‘char* const*’ to ‘char**’ [-fpermissive]
if( !PyArg_ParseTupleAndKeywords( args, kwargs, "s|s", kwlist, &path, ®ex ) ) {
^
In file included from /usr/include/python3.6m/Python.h:117:0,
from source/test.cpp:3:
/usr/include/python3.6m/modsupport.h:17:41: note: initializing argument 4 of ‘int _PyArg_ParseTupleAndKeywords_SizeT(PyObject*, PyObject*, const char*, char**, ...)’
#define PyArg_ParseTupleAndKeywords _PyArg_ParseTupleAndKeywords_SizeT
^
/usr/include/python3.6m/modsupport.h:17:41: note: in definition of macro ‘PyArg_ParseTupleAndKeywords’
#define PyArg_ParseTupleAndKeywords _PyArg_ParseTupleAndKeywords_SizeT
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: command 'x86_64-linux-gnu-gcc' failed with exit status 1
How can I get rid of the warning using an equivalent construct to static char* kwlist[] = {"a", "b", NULL}
with C++ 11
while being compatible with Python C API requirements?
After suggested I tried static const char* kwlist[] = {"a", "b", NULL}
but PyArg_ParseTupleAndKeywords
does not accept it:
source/test.cpp:43:89: error: invalid conversion from ‘const char**’ to ‘char**’ [-fpermissive]
if( !PyArg_ParseTupleAndKeywords( args, kwargs, "s|s", kwlist, &filepath, &rawregex ) ) {
^
In file included from /usr/include/python3.6m/Python.h:117:0,
from source/test.cpp:3:
/usr/include/python3.6m/modsupport.h:17:41: note: initializing argument 4 of ‘int _PyArg_ParseTupleAndKeywords_SizeT(PyObject*, PyObject*, const char*, char**, ...)’
#define PyArg_ParseTupleAndKeywords _PyArg_ParseTupleAndKeywords_SizeT
^
/usr/include/python3.6m/modsupport.h:17:41: note: in definition of macro ‘PyArg_ParseTupleAndKeywords’
#define PyArg_ParseTupleAndKeywords _PyArg_ParseTupleAndKeywords_SizeT
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: command 'x86_64-linux-gnu-gcc' failed with exit status 1
The sample code you copied from is probably C, where the warning isn't as seriously considered (gcc
reports no error on such a code, where g++
pops a warning even with no warning options).
The fix here is to add const
keyword like this:
static const char* kwlist[] = {"a", "b", NULL};
The const
keyword you tried wasn't applying to the values but to the pointers.
Then to make the function accept a char **
use const_cast
:
const_cast<char **>(kwlist)
like this:
PyArg_ParseTupleAndKeywords( args, kwargs, "s|s", const_cast<char **>(kwlist), &path, ®ex ) )
The function isn't going to change the values by implicit "contract" (because it's python API, it's not going to lie to you), so in this case, casting to const is fine)
PS: The alternative given by this other answer also works. Note that using empty mutable strings is not safer than casting to constant, as if the called function decided to write into empty strings, it would also invoke undefined behaviour.