Какова текущая практика использования строк в кроссплатформенных API C и C ++? - PullRequest
10 голосов
/ 26 июля 2011

Похоже, мне, возможно, понадобится начать какой-то кроссплатформенный проект, и часть его должна быть сделана на C или C ++ (пока не решено, поэтому вопрос о них обоих). Я буду иметь дело в основном с текстовыми материалами и строками в целом.

То, что C / C ++ будет иметь API, вызываемый из более зависимого от платформы кода.

Мой вопрос: Какой тип (ы) целесообразно использовать для работы со строками, особенно при объявлении открытых интерфейсов? Есть ли рекомендуемые стандартные методы? Есть ли вещи, которых следует избегать?

У меня небольшой опыт написания кода на C или C ++, и даже это было в Windows, так что здесь нет ничего похожего на кроссплатформенность. Итак, что я действительно ищу, так это что-то, что поможет мне встать на правильный путь и избежать глупостей, которые могут причинить много боли.


Редактировать 1: Чтобы получить немного больше информации о предполагаемом использовании. API будет использоваться:

  • Цель C на iPhone / iPad / Mac через NSString и друзей. API может быть статически связан, поэтому не нужно беспокоиться о проблемах .so .dll здесь.

  • Java через JNI на Android и других платформах Java

  • .NET через p / invoke из управляемого кода C # или изначально статически связаны при использовании C ++ / CLI.

  • Есть некоторые мысли об использовании lua как-то / где-то в этом контексте. Не знаю, имеет ли это какое-либо отношение к чему-либо.

Ответы [ 4 ]

15 голосов
/ 26 июля 2011

Правила

  • Используйте форматы UTF для хранения строк, не"кодовые страницы" или еще много чего ( UTF-16, вероятно, проще редактировать: я полностью забыл о проблемах порядка байтов; UTF -8, вероятно, путь).

  • Используйте строки с нулевым символом в конце вместо подсчитанных строк, так как к ним проще всего обращаться из большинства языков. Но будьте осторожны с переполнением буфера.
    Обновление 6 лет спустя: Я рекомендовал этот API по причинам функциональной совместимости (поскольку многие уже используют нулевое завершение, и существует несколько способов представления подсчитанных строк), не самый лучший с точки зрения наилучшей разработки. Сегодня я бы сказал, что первый вариант менее важен, и рекомендую использовать счетные строки, а не строки с нулевым символом в конце, если вы можете это сделать.

  • Даже не пытайтесь использовать такие классы, как std::string, для передачи строк пользователю. Даже ваша собственная программа может выйти из строя после обновления вашего компилятора / библиотек (поскольку их детали реализации - это просто детали реализации), не говоря уже о том, что программы не на C ++ будут иметь проблемы с этим.
    Обновление 6 лет спустя: Это строго из соображений совместимости языка и ABI с другими языками , а не с общими советами по разработке программ на C ++. Если вы занимаетесь разработкой на C ++, кроссплатформенным или другим способом, используйте STL! То есть, следуйте этому совету только в том случае, если вам нужно вызывать код с других языков.

  • Старайтесь не выделять строки для пользователя, если в противном случае пользователю не будет действительно больно. Вместо этого возьмите буфер и заполните его данными. Таким образом, вам не нужно заставлять пользователя использовать определенную функцию для освобождения данных. (Это также часто является преимуществом с точки зрения производительности, поскольку позволяет пользователю выделять небольшие буферы в стеке. Но если вы делаете , то обеспечивает вашу собственную функцию для освобождения данных Вы не можете предполагать, что ваши malloc или new могут быть освобождены с помощью их free или delete - они часто не могут быть.)

Примечание:

Просто чтобы уточнить, "разрешить пользователю выделять буфер" и "использовать строки, заканчивающиеся на NULL", не работают друг против друга. Вам все еще нужно получить длину буфера от пользователя, но вы включаете NULL, когда завершаете строку. Моя точка зрения была , а не , что вы должны сделать функцию, аналогичную scanf("%s"), что, очевидно, необычайно опасно - вам все еще нужна длина буфера от пользователя. то есть делать в значительной степени то, что Windows делает в этом отношении.

4 голосов
/ 26 июля 2011

Если вы хотите, чтобы 10-тонный молоток имел дело со строками в C / C ++, тогда проект ICU IBM для вас.http://site.icu -project.org /

В ICU есть все инструменты для работы со строками с действительно хорошей поддержкой юникода.Это впечатляющий и хорошо поддерживаемый продукт с открытым исходным кодом с благоприятной лицензией для коммерческих проектов.

Если вы хотите выпустить свой код как .dll / .so, чтобы другие могли его вызывать, то вы, вероятно, хотите свести к минимумуваши внешние зависимости.В этом случае вы можете придерживаться стандартных библиотек или более легкого проекта.

4 голосов
/ 26 июля 2011

Что C / C ++ будет иметь API, вызываемый из более высокого уровня зависимый от платформы код.

Если под этим вы подразумеваете, что вы хотите, чтобы эта библиотека была библиотекой DLL, которую можно вызывать из других языков, например из языков .NET, тогда я настоятельно рекомендую использовать все публичные API как функции extern "C", которые имеют только типы POD. в качестве параметров и возвращаемых значений. То есть предпочитают /*const*/ char*, а не std::string. Помните, C ++, в отличие от простого C, не имеет стандартного ABI.

1 голос
/ 26 июля 2011

Очень распространенный способ вернуть строку вызывающей стороне - это принять указатель буфера строки и количество символов размера буфера.Полезное соглашение - возвращать количество символов, скопированных в буфер, в качестве возвращаемого значения;это особенно ценно, если вы рассматриваете размер буфера 0 как особый случай и возвращаете необходимое количество символов (включая нулевой терминатор).

int GetString(char * buffer, int buffersize);

В C ++ удобно работать с stdВместо этого :: string, но это создает проблему: вы не можете полагаться на реализацию std :: string для совместимости между различными скомпилированными частями программы, то есть между вашей основной программой и библиотекой.Предоставляя встроенную функцию в заголовочном файле, вы можете убедиться, что std :: string создается в том же контексте, что и вызывающая программа, и обойти эту проблему.

inline std::string GetString()
{
    std::string result(GetString(NULL, 0), 0);
    GetString(&result[0], result.size());
    result.erase(result.size() - 1);
    return result;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...