Кажется, что Python C API не согласуется с константной корректностью символьных массивов. Например, PyImport_ImportFrozenModule принимает char*
, в то время как PyImport_ImportModule принимает const char*
,
Следствием всего этого является то, что в моем приложении C ++, которое я пишу со встроенным интерпретатором Python, мне иногда приходится приводить строковый литерал, который я передаю, к вызову Python API как char*
(в отличие от const char*
), а иногда нет. Например:
PyObject *os = PyImport_ImportModule("os"); // Works without the const_cast
PyObject *cwd = PyObject_CallMethod(os, const_cast<char*>("getcwd"), NULL); // Accepts char*, not const char*
Если я не сделаю const_cast<char*>
(или же (char*)
) в строковом литерале я получаю предупреждение компилятора о приведении строковых литералов в char*
,
Вот мои вопросы:
const char*
(и / или почему бы Python API не был последовательным в этом)? Насколько я понимаю, что если функция может принимать строковый литерал, она не может изменить char*
Итак const
Модификатор будет только усиливать это. Я также считаю, что const
Различие не так важно для C (для которого был написан API), чем для C ++ (поправьте меня, если я ошибаюсь … моя сила в Python, а не в C / C ++). Является ли отсутствие «правильной константности» Python API, потому что это просто не так важно в C? (Есть старая ветка в списке рассылки python с 2000 года, задавая тот же вопрос, но он, похоже, никуда не ушел, и подразумевается, что причина может быть в том, что некоторые компиляторы не поддерживают const
, Поскольку многие функции теперь имеют const char*
кажется, это больше не применимо)Поскольку мое понимание C ++ ограничено, я не уверен, правильно ли я приведу строковые литералы. На мой взгляд, я могу выполнить одно из следующих действий (сейчас я делаю первый):
// Method 1) Use const_cast<char*>
PyImport_ImportFrozenModule(const_cast<char*>("mymodule"));
// Method 2) Use (char*)
PyImport_ImportFrozenModule((char*) "mymodule");
// Method 3) Use char array
char mod[] = "mymodule";
PyImport_ImportFrozenModule(mod);
Какой метод лучше использовать?
Обновить:
Похоже, ветка Python3 медленно пытается исправить проблему правильности констант. Например, PyImport_ImportFrozenModule
Функция, которую я использую в качестве примера выше, теперь занимает const char*
в Python 3.4, но все еще есть функции, которые принимают только char*
, такие как PyLong_FromString.
Судя по некоторым разговорам в списке рассылки от python-dev, похоже, что первоначальный API просто не был создан с учетом константности, вероятно, просто потому, что Гвидо не думал об этом. Встречаясь в 2002 году, кто-то спросил если было желание решить эту проблему, добавив const -корректность, жалуясь, что всегда приходится делать это так:
somefunc(const char* modulename, const char* key)
{
... PyImport_ImportModule(const_cast<char*>(modulename)) ...
Гвидо Ван Россум (создатель Python) ответил (выделение мое):
Я никогда не пытался применить константность, но я слышал
достаточно ужасных историй об этом. Проблема в том, что он ломает 3-й
партийные расширения влево и вправо, и исправить их не всегда просто.
В общем, всякий раз, когда вы добавляете const где-то, это заканчивается распространением
к другому API, который затем также требует const, который распространяется
еще одному API, нуждающемуся в const, до бесконечности.
Было немного больше дискуссий, но без поддержки Гвидо идея умерла.
Перенесемся на девять лет, и тема снова возникла. На этот раз кто-то просто задавался вопросом, почему некоторые функции были правильными, а другие — нет. Один из разработчиков ядра Python ответил с этим:
На протяжении многих лет мы добавляли const во многие места. я думаю
конкретный случай был пропущен (т.е. никто не заботился о добавлении const
там).
Кажется, что когда это можно было бы сделать, не нарушая обратную совместимость, const -корректность была добавлена во многие места в C API (и в случае с Python 3, в местах, где это было бы нарушить обратную совместимость с Python 2), но глобальных усилий по ее устранению не было везде. Таким образом, ситуация лучше в Python 3, но весь API, вероятно, не является правильным даже сейчас.
Я не думаю, что у сообщества Python есть какой-либо предпочтительный способ обрабатывать приведение с вызовами, которые не являются const
-правильно (нет упоминания об этом в официальном Руководство по стилю C-API), вероятно, потому, что нет тонны людей, взаимодействующих с C-API из кода C ++. Я бы сказал, что предпочтительным способом сделать это с точки зрения передового опыта в чистом C ++ будет первый выбор. (Я ни в коем случае не эксперт C ++, так что возьмите это с крошкой соли).
Есть ли преимущество / причина того, что некоторые функции не
const char*
?
Нет. Выглядит как упущение в дизайне библиотеки или, как вы говорите, унаследованные проблемы. Хотя бы они могли сделать это непротиворечивым!
Насколько я понимаю, что если функция может принимать строковый литерал, она не может изменить
char*
Итакconst
Модификатор будет только усиливать это.
Именно так. В их документации также должно быть указано, что аргумент функции (или, скорее, аргумент аргумента) не должен изменяться во время вызова функции; увы это сейчас не говорит об этом.
Я также считаю, что
const
Различие не так важно для C (для которого был написан API), чем для C ++.
Ну, не совсем, по крайней мере, насколько я знаю.
На мой взгляд, я могу выполнить одно из следующих действий (сейчас я делаю первый)
(хорошо)
Какой метод лучше использовать?
Хорошо const_cast
по крайней мере, убедитесь, что вы только модифицирование const
Конечно, если бы тебе пришлось выбирать, я бы пошел с этим. Но, на самом деле, я бы не стал слишком беспокоиться об этом.