Почему strlen() возвращает 64-битное целое число? Я что-то упускаю?

Почему при компиляции 64-битного приложения функция strlen() возвращает 64-битное целое число? Я что-то упустил?

Я понимаю, что strlen() возвращает тип size_t, и по определению это не должно меняться, но... Зачем strlen нужно возвращать 64-битное целое число?

Функция предназначена для использования со строками. При этом сказал:

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

Я думаю, что это смешно, на самом деле, возможно, нам нужна функция StrLenAsync() с обратным вызовом только для обработки сверхдолгого процесса поиска NULL в строке 40 ТБ. Звучит глупо? Да, strlen() возвращает 64-битное целое число!

Конечно, предлагаемая функция StrLenAsync() — это шутка.


person NTDLS    schedule 14.07.2009    source источник
comment
Почему вы думаете, что size_t не меняется в зависимости от платформы?   -  person Yacoby    schedule 14.07.2009
comment
Строки с завершающим нулем в любом случае глупы, так что какая разница? ;)   -  person OregonGhost    schedule 14.07.2009
comment
@NTDLS: на 64-битной платформе нет реальных накладных расходов при возврате 64-битного целого числа, поскольку оно помещается в один регистр. (Предполагая, что для возвращаемого значения используется регистр, что имеет место на большинстве платформ, которые я видел).   -  person Evan Teran    schedule 14.07.2009
comment
Итак, strlen() возвращает size_t. У вас есть проблема с тем, что size_t является 64-битным на 64-битной платформе, или strlen() должна возвращать какой-то специальный funkystringsize_t?   -  person Gleb    schedule 14.07.2009
comment
Если вас это так сильно беспокоит, используйте std::string. Больше не нужно искать NULL в строке размером 40 ТБ.   -  person Mark Ransom    schedule 14.07.2009
comment
Это не проблема, так как я выделяю свои 40 ТБ строк только на машинах, которые могут выполнить бесконечный цикл менее чем за 3 секунды.   -  person Steven Sudit    schedule 15.07.2009
comment
Самое главное, strlen возвращает 64-битное беззнаковое целое число;) size_t будет самым большим целочисленным типом без знака в соответствии с архитектурой.   -  person Tim Post♦    schedule 08.03.2010


Ответы (7)


Похоже, что при компиляции для 64-битной цели size_t определяется как 64-битная. Это имеет смысл, так как size_t используется для размеров всех видов объектов, а не только строк.

person Steven Sudit    schedule 14.07.2009
comment
Полностью понятно, но разве это не много накладных расходов для функции, которая, вероятно, никогда не увидит возвращаемого значения, превышающего максимальное 32-битное целое число без знака? - person NTDLS; 14.07.2009
comment
Чтобы разница между двумя указателями была точной. И strlen именно это. - person Marco van de Voort; 14.07.2009
comment
Это все равно, что сказать, что 32-битный size_t имеет 16 бит служебных данных, потому что большинство строк намного меньше 64 КБ. :-) - person Steven Sudit; 14.07.2009
comment
Это все равно, что сказать, что 'bool' имеет по крайней мере 1 бит служебных данных, потому что строки часто пусты. -- извините, не удержался - person Aaron; 14.07.2009
comment
Ну, это больше похоже на то, что bool имеет 7 битов служебной информации, потому что стоимость упаковки битов с помощью ands и ors превышает экономию места. - person Steven Sudit; 14.07.2009
comment
size_t составляет 64 бита на 64-битных машинах. На таких машинах нет накладных расходов, поскольку регистр имеет длину 64 бита и обычно возвращаемое значение находится в регистре. На самом деле было бы пустой тратой времени определять size_t как 32 бита. - person Jared Oberhaus; 14.07.2009
comment
@NTDLS: Написание кода, который хорошо себя ведет только в ситуациях, которые кто-то считает вероятными, является частой причиной ошибок - и, что еще хуже, недостатков безопасности. Даже после того, как он был использован бесчисленное количество раз, многие люди все еще думают, что маловероятно, что кто-то введет необработанный SQL в URL-адрес браузера и просканирует базу данных, полную номеров кредитных карт. - person Bob Murphy; 15.10.2009
comment
@Jared: Ну, в регистре нет накладных расходов, но если он попадет в переменную, он будет использовать вдвое больше оперативной памяти. Это проблема? С одной стороны, это означает более раннее проедание кеша. С другой стороны, 64-битные процессоры могут обрабатывать тонны оперативной памяти. Я бы назвал это стиркой. - person Steven Sudit; 15.10.2009
comment
Для разницы между двумя указателями (которая может быть отрицательной) используется ptrdiff_t. size_t используется для неотрицательных вещей. - person Johannes Schaub - litb; 18.02.2010

В 64-битном приложении определенно можно создать строку размером 5 ГБ.

Спецификация не предназначена для того, чтобы удерживать вас от глупых поступков.

Даже если бы в этом не было необходимости, не стоило бы менять спецификацию strlen вместо использования size_t только для того, чтобы возвращаемое значение равнялось 4 байтам вместо 8.

person Tim Sylvester    schedule 14.07.2009
comment
В 32-битном приложении также возможно создать строку размером 5 ГБ. Его просто нельзя сразу отобразить в 32-битное адресное пространство, так что strlen должен быть умным в этом вопросе, а это не так. Подробнее см. в следующей интересной статье: .aspx" rel="nofollow noreferrer">blogs.msdn.com/ericlippert/archive/2009/06/08/ - person OregonGhost; 14.07.2009
comment
Функция strlen работает с указателем, предполагая, что строка следует за ним в непрерывной памяти. 32-битный указатель не может представлять строку размером более 4G (за вычетом того места, которое резервирует операционная система) в памяти. Хотя существует несколько способов представления строк, превышающих размер адресного пространства, они не имеют отношения к strlen из-за допущений, встроенных в его спецификацию. - person Tim Sylvester; 14.07.2009

Вот диаграмма, показывающая размер некоторых базовых типов в наиболее распространенных моделях данных:

         LP32 ILP32 LP64 LLP64 ILP64
char       8    8     8     8     8
short     16   16    16    16    16
int       16   32    32    32    64
long      32   32    64    32    64
long long 64   64    64    64    64
pointer   32   32    64    64    64
size_t    32   32    64    64    64

Модель данных 32-разрядной Windows — ILP32, а модель данных 64-разрядной Windows — LLP64. (Модель данных Windows 3.1 и Macintosh была LP32.)

person Nick    schedule 14.07.2009
comment
Я надеялся, что это может быть полезно. В настоящий момент я занимаюсь переносом очень большой кодовой базы C++ на 64-разрядную версию, поэтому я живу и дышу этим материалом прямо сейчас. - person Nick; 14.07.2009
comment
Да, очень красивый график. Я сохранил копию. - person NTDLS; 15.07.2009

Я могу вспомнить несколько приложений, в которых строки из 4 ГБ просто недостаточно (вычислительная биология, компьютерная криминалистика — два ОГРОМНЫХ приложения). Не думайте, что если ВЫ этого не делаете, то и никто другой этого не делает.

person San Jacinto    schedule 14.07.2009
comment
О нет, я это прекрасно понимаю. Я просто говорю, что вы не хотели бы передавать этот массив символов размером более 4 ГБ в функцию strlen(). Вам просто может быть лучше следить за его длиной, пока вы его строите. - person NTDLS; 15.07.2009
comment
Мы не используем строки размером 4 ГБ в компьютерной криминалистике. Это было бы глупо. - person vy32; 18.02.2010
comment
Вы никогда не индексировали весь жесткий диск для последующего изучения? Как насчет того, когда со сцены забирают мобильный телефон? Легче индексировать содержимое SD-карты, чем постоянно читать с карты. Если вы имеете в виду использование strlen() для определения длины строки размером 4 ГБ, то да, это глупо. В противном случае, я не думаю, что я тут дурак... - person San Jacinto; 18.02.2010

Дело не в том, будет ли кто-нибудь на самом деле создавать строку такого размера. По соглашению, ВСЕ возвращаемые типы, которые указывают количество байтов, занимаемых в памяти, имеют размер_t.

person Larry Gritz    schedule 14.07.2009

Что ж, 1) size_t — это typedef, зависящий от архитектуры, и 2) не имеет ли смысла иметь наибольшее целое число в качестве возвращаемого значения? Почему 32 бита? Почему не 16? На вашем компьютере это 64, потому что это максимально возможная длина строки.

person Tyler    schedule 14.07.2009

strlen() должны использовать возвращаемый тип, который может представлять размер самого большого объекта в модели размещения.

Вы можете использовать std::string. Его size_type равно size_type распределителя. Итак, если вы создадите свой собственный распределитель, то std::string::size() может использовать даже char в качестве возвращаемого типа.

Спасибо за замечание в комментариях. std::string - это просто специализация std::basic_string. Конечно, вы должны использовать std::basic_string с настраиваемым распределителем.

person Kirill V. Lyadvinsky    schedule 14.07.2009
comment
Вы не можете (в стандартном С++) изменить распределитель для std::string: это typedef, а не шаблон. Вы должны использовать basic_string. - person Steve Jessop; 14.07.2009