Отключение NUL-завершения строк в GCC

Можно ли глобально отключить строки с NUL-окончанием в GCC?

Я использую свою собственную библиотеку строк, и у меня нет абсолютно никакой потребности в конечных символах NUL, поскольку она уже хранит надлежащую длину внутри структуры.

Тем не менее, если бы я хотел добавить 10 строк, это означало бы, что 10 байтов излишне выделяются в стеке. С широкими строками это еще хуже: что касается x86, то теряется 40 байт; а для x86_64 80 байт!

Я определил макрос для добавления этих выделенных стеком строк в мою структуру:

#define AppendString(ppDest, pSource) \
  AppendSubString(ppDest, (*ppDest)->len + 1, pSource, 0, sizeof(pSource) - 1)

С помощью sizeof(...) - 1 работает довольно хорошо, но мне интересно, смогу ли я избавиться от завершения NUL, чтобы сэкономить несколько байтов?

7 ответов

Решение

Это довольно ужасно, но вы можете явно указать длину каждой константы массива символов:

char my_constant[6] = "foobar";
assert(sizeof my_constant == 6);

wchar_t wide_constant[6] = L"foobar";
assert(sizeof wide_constant == 6*sizeof(wchar_t));

Я понимаю, что вы имеете дело только со строками, объявленными в вашей программе:

 ....
 char str1[10];
 char str2[12];
 ....

а не с текстовыми буферами, которые вы выделяете с malloc() а друзья иначе sizeof не поможет тебе.

В любом случае, я бы дважды подумал об удалении \0 в конце: вы потеряете совместимость со стандартными функциями библиотеки C.

Если вы не собираетесь переписывать какую-либо одностроковую функцию для вашей библиотеки (например, sprintf), вы уверены, что хотите это сделать?

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

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

Наличие оболочки, которая использует strlen для определения длины строки и не встроена, почти наверняка сэкономит больше места.

Разве они не похожи на струны в стиле Паскаля или на Холлерит? Я думаю, что это полезно только в том случае, если вы действительно хотите, чтобы данные String сохраняли значения NULL, в которых вы действительно перемещаете произвольную память, а не "строки" как таковые.

Я не могу вспомнить детали, но когда я делаю

char my_constant[5]

Вполне возможно, что он все равно зарезервирует 8 байтов, потому что некоторые машины не могут адресовать середину слова.

Почти всегда лучше оставить этот тип компилятору и позволить ему обработать выбор за вами, если только для этого нет действительно веской причины.

На самом деле это только в том случае, если у вас действительно мало памяти. В противном случае я не рекомендую это делать.

Кажется, самый правильный способ сделать то, о чем вы говорите, это:

  • Чтобы подготовить минимальный файл листинга в виде:
    string1_constant_name "str1"
    string2_constant_name "str2"...
  • Для создания утилиты, которая обрабатывает ваш файл и генерирует объявления, такие как
    const char string1_constant[4] = "str1";

Конечно, я бы не советовал делать это руками, потому что в противном случае у вас могут возникнуть проблемы после любого изменения строки.

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

Преимуществами являются легкая локализация, возможность добавить некоторый уровень проверок, чтобы снизить риск этого решения, и экономия сегмента данных R/O.

Недостатком является необходимость включения всех таких строковых констант в каждый модуль (например, include, чтобы держать sizeof() известным). Так что это имеет смысл, только если ваш компоновщик объединяет такие символы (некоторые этого не делают).

Если вы не используете какую-либо функцию стандартной библиотеки, которая работает со строками, вы можете забыть о завершающем байте NUL.

нет strlen() нет fgets() нет atoi() нет strtoul() нет fopen() нет printf() с %s спецификатор преобразования...

Объявите ваши "не совсем строки C" только с необходимым пространством;

struct NotQuiteCString { /* ... */ };

struct NotQuiteCString variable;
variable.data = malloc(5);
data[0] = 'H'; /* ... */ data[4] = 'o'; /* "hello" */
Другие вопросы по тегам