Что такое размер 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*)