Путаница size_t в таких функциях, как snprintf

В таких функциях, как snprintf, strlcat и strlcpy, где их справочная страница упоминает size_t size в аргументах указанных функций, что такое size или как лучше всего получить size?

Взято из strlcpy(3), strcat(3) и printf(3) (с добавленными комментариями)

size_t
strlcpy(char *dst, const char *src, size_t size);
//                                         ^^^^

char *
strncat(char *str, const char *src, size_t n);
//                                         ^

int
snprintf(char *str, size_t size, const char *format, ...);
//                         ^^^^  

Я так понимаю, что size можно (или, в случае strncat, нужно?) получить так:

sizeof dst - strlen(dst) - 1 
// sizeof dst buffer, minus the offset of '\0', minus 1 for the null-terminator

Но я помню, как читал где-то на SO, чтобы получить size переменной, которую вы сделали что-то вроде:

sizeof <VAR> / <SOMETHING ELSE?>
// sorry, I don't remember the rest of this method

Есть ли разница между этими двумя формами, являются ли они эквивалентными и/или взаимозаменяемыми, или они действительны только при определенных обстоятельствах?

EDIT: я думаю, что теперь я понимаю это немного лучше. sizeof возвращает размер в байтах того, что вы ему передаете, но в тех же случаях вам необходимо учитывать размер целевого буфера в дополнение к размеру исходного буфера, как в случае strncat.


person Alexej Magura    schedule 24.12.2014    source источник
comment
size_t обычно (но не всегда) можно рассматривать как целое число без знака. он используется для переносимости. sizeof — это оператор времени компиляции, который возвращает количество байтов в некотором объекте. ваш пример: sizeof ‹VAR› / ‹SOMETHING ELSE?› часто используется для получения количества записей в таблице путем кодирования: sizeof (таблица) / sizeof (одна запись в таблице)   -  person user3629249    schedule 24.12.2014
comment
@user3629249 user3629249, думал, что он имеет тип целого числа без знака.   -  person ChiefTwoPencils    schedule 24.12.2014
comment
strlen(dst) (для строки с завершающим нулем) получает смещение нулевого байта в конце строки. Однако, поскольку смещения начинаются с 0, это (также) количество байтов в строке.   -  person user3629249    schedule 24.12.2014
comment
учитывая эту строку: 'sizeof dst - strlen (dst) - 1', это фактически дает количество байтов в dst, которые НЕ заняты (строка + нулевой байт-терминатор), т.е. если dst равно 30 байтам, а strlen возвращает 20 байтов, то количество неиспользуемых байтов равно: 30 - 20 -1 = 9 неиспользуемых байтов.   -  person user3629249    schedule 24.12.2014
comment
size_t — это тип unsigned, способный хранить размер максимально возможного объекта. Будем надеяться, что это по крайней мере unsigned int (нет гарантии, желательно из-за целочисленного продвижения по умолчанию), хотя с таким же успехом может быть и unsigned long long.   -  person Deduplicator    schedule 24.12.2014


Ответы (1)


Для strlcpy вы указываете размер буфера. Если буфер имеет размер 100, strlcpy может скопировать до 99 символов плюс нулевой байт.

Для strlcat вы указываете размер буфера. strlcat вычисляет, сколько байт уже имеется.

Весь смысл strlcpy, strlcat, snprintf заключается в том, что вы указываете размер буфера, а функция вычисляет остальное, вместо того, чтобы вычислять, сколько байтов доступно. Это связано с тем, что люди, вычисляющие размеры, допускают ошибки, поэтому вызов strlcpy и самостоятельное вычисление количества доступных байтов лишают цели.

person gnasher729    schedule 24.12.2014