Что такое размер t в C?
я путаюсь с size_t
в C. Я знаю, что он возвращается sizeof
оператора. Но что это такое? Это тип данных?
Допустим у меня есть for
петли:
for(i = 0; i < some_size; i++)
должен ли я использовать int i;
или size_t i;
?
11 ответов
согласно стандарту ИСО к 1999 (C99),
size_t
- целое число без знака тип не менее 16 бит (см. разделы 7.17 и 7.18.3).
size_t
- тип данных без знака определяется несколькими стандартами C / C++ , например, стандарт C99 ISO / IEC 9899, это определено вstddef.h
.1 он может дальнейшее ввозимых включенияstdlib.h
как этот файл внутренне sub включаетstddef.h
.этот тип используется для представления размер объекта. Библиотечная функция которые принимают или возвращают размеры ожидают их типа или типа возврата из
size_t
. Далее, наиболее часто используемый компилятор оператор sizeof должен оценить в a постоянное значение, совместимое сsize_t
.
как импликация, size_t
- тип, который гарантированно содержит любой индекс массива.
size_t
- тип без знака. Таким образом, он не может представлять отрицательные значения(strlen()
возвращает size_t
потому что длина строки должна быть не менее 0.
в вашем примере, если ваш индекс цикла всегда будет больше 0, может иметь смысл использовать size_t
, или любой другой беззнаковый тип данных.
при использовании size_t
объект, вы должны убедиться, что во всех контекстах он используется, включая арифметику, вы хотите неотрицательные значения. Например, предположим, у вас есть:
size_t s1 = strlen(str1);
size_t s2 = strlen(str2);
и вы хотите найти разницу длин str2
и str1
. Вы не можете сделать:
int diff = s2 - s1; /* bad */
это потому, что значение, присвоенное diff
всегда будет положительным числом, даже когда s2 < s1
, потому что вычисление выполняется с неподписанными типами. В этом случае, в зависимости от каков ваш вариант использования, вам может быть лучше использовать int
(или long long
) для s1
и s2
.
в C / POSIX есть некоторые функции, которые могут/должны использовать size_t
, но не из-за исторических причин. Например, второй параметр fgets
в идеале должно быть size_t
, но это int
.
size_t
- Это тип, который может содержать любой индекс массива.
в зависимости от реализации, это может быть любой из:
unsigned char
unsigned short
unsigned int
unsigned long
unsigned long long
вот как size_t
определена в stddef.h
моя машина:
typedef unsigned long size_t;
если вы эмпирический тип
echo | gcc -E -xc -include 'stddef.h' - | grep size_t
выход для Ubuntu 14.04 64-бит GCC 4.8:
typedef long unsigned int size_t;
отметим, что stddef.h
предоставляется GCC, а не glibc под src/gcc/ginclude/stddef.h
в GCC 4.2.
интересные выступления C99
-
malloc
принимаетsize_t
как аргумент, он определяет максимальный размер, который может быть выделен.и так как он также возвращается
sizeof
, Я думаю, что это ограничивает максимальный размер любого массива.Читайте также: максимальный размер массива в C
manpage для типы.h говорит:
size_t должен быть целочисленным типом без знака
поскольку никто еще не упомянул об этом, основное лингвистическое значение size_t
Это sizeof
оператор возвращает значение этого типа. Аналогично, первичное значение ptrdiff_t
это вычитание одного указателя из другого даст значение этого типа. Библиотечные функции, которые принимают его, делают это, потому что это позволит таким функциям работать с объектами, размер которых превышает UINT_MAX в системах, где такие объекты могут существовать, не заставляя вызывающих абонентов тратить код, передающий значение больше, чем" unsigned int " в системах, где для всех возможных объектов достаточно большего типа.
size_t
и int
не заменимы. Например, на 64-битном Linux size_t
имеет 64-битный размер (т. е. sizeof(void*)
), но int
32-битные.
также обратите внимание, что size_t
не подписан. Если вам нужна подписанная версия, то есть ssize_t
на некоторых платформах, и это было бы более уместно для вашего примера.
как общее правило, я бы предложил использовать int
для большинства общих случаев и использовать только size_t
/ssize_t
когда специфическая потребность для его (с mmap()
например).
В общем случае, если вы начинаете с 0 и идете вверх, всегда используйте тип без знака, чтобы избежать переполнения, приводящего вас в ситуацию с отрицательным значением. Это критически важно, потому что, если ваши границы массива будут меньше, чем max вашего цикла, но ваш цикл max будет больше, чем max вашего типа, вы обернете вокруг отрицательного, и вы можете испытать ошибка сегментирования (сигнала SIGSEGV). Таким образом, в общем случае никогда не используйте int для цикла, начинающегося с 0 и идущего снизу вверх. Используйте unsigned.
size_t-это беззнаковый целочисленный тип данных. В системах, использующих библиотеку GNU C, это будет unsigned int или unsigned long int. size_t обычно используется для индексации массива и подсчета циклов.
реализация или любой неподписанный тип может рассматриваться как переменная цикла, поскольку переменные цикла обычно больше или равны 0.
при использовании реализация объект, мы должны убедиться, что во всех контекстах он используется, включая арифметику, мы хотим только неотрицательные значения. Например, следующая программа определенно даст неожиданный результат:
// C program to demonstrate that size_t or
// any unsigned int type should be used
// carefully when used in a loop
#include<stdio.h>
int main()
{
const size_t N = 10;
int a[N];
// This is fine
for (size_t n = 0; n < N; ++n)
a[n] = n;
// But reverse cycles are tricky for unsigned
// types as can lead to infinite loop
for (size_t n = N-1; n >= 0; --n)
printf("%d ", a[n]);
}
Output
Infinite loop and then segmentation fault
в моем понимании, size_t
это unsigned
целое число, размер бита которого достаточно велик, чтобы содержать указатель собственной архитектуры.
Так:
sizeof(size_t) >= sizeof(void*)