Меня путают с size_t
в C. Я знаю, что он возвращается оператором sizeof
. Но что именно? Это тип данных?
Скажем, у меня есть for
цикл:
for(i = 0; i < some_size; i++)
Что мне использовать: int i;
или size_t i;
?
Меня путают с size_t
в C. Я знаю, что он возвращается оператором sizeof
. Но что именно? Это тип данных?
Скажем, у меня есть for
цикл:
for(i = 0; i < some_size; i++)
Что мне использовать: int i;
или size_t i;
?
Согласно стандарту ISO C (C99) 1999 г.,
size_t
- это беззнаковый целочисленный тип длиной не менее 16 бит (см. Разделы 7.17 и 7.18.3).
size_t
- это беззнаковый тип данных, определенный несколькими стандартами C / C ++, например. стандарт C99 ISO / IEC 9899, который определен вstddef.h
. 1 Его можно дополнительно импортировать с помощью включениеstdlib.h
, поскольку этот файл внутренне включаетstddef.h
.Этот тип используется для представления размера объекта. Библиотечные функции, которые принимают или возвращают размеры, ожидают, что они будут иметь тип или возвращаемый тип
size_t
. Кроме того, наиболее часто используемый оператор на основе компилятора sizeof должен оцениваться как постоянное значение, совместимое сsize_t
.
Как следствие, size_t
- это тип, который гарантированно содержит любой индекс массива.
size_t
предназначен для объектов в памяти. Стандарт C даже не определяет stat()
или off_t
(это определения POSIX) или чего-либо, связанного с дисками или файловыми системами - он останавливается на FILE
потоках. Управление виртуальной памятью полностью отличается от файловых систем и управления файлами в том, что касается требований к размеру, поэтому упоминание off_t
здесь неуместно.
- person jw013; 10.06.2013
size_t
как тип результата оператора sizeof
(7.17p2 о <stddef.h>
). Раздел 6.5 объясняет, как именно работают выражения C (6.5.3.4 для sizeof
). Поскольку вы не можете применить sizeof
к файлу на диске (в основном потому, что C даже не определяет, как работают диски и файлы), здесь нет места для путаницы. Другими словами, вините Википедию (и этот ответ за цитирование Википедии, а не фактического стандарта C).
- person jw013; 14.06.2013
size_t
(почти наверняка) является typedef для некоторого существующего целочисленного типа без знака. Например, size_t
обычно того же типа, что и unsigned long
(typedef создает псевдоним для существующего типа, а не для нового типа). Но вы не должны предполагать, что size_t
- это то же самое, что и любой конкретный тип, поскольку он может варьироваться от системы к системе.
- person Keith Thompson; 06.08.2015
size_t
- беззнаковый тип. Таким образом, он не может представлять никаких отрицательных значений (‹0). Вы используете его, когда что-то считаете, и уверены, что это не может быть отрицательным. Например, 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
? 2) почему я должен предпочесть size_t
чему-то вроде unsigned int
?
- person Lazer; 08.06.2010
size_t
не обязательно будет тем же, что и unsigned int
(вы, кажется, имеете в виду, что они такие же).
- person Brendan Long; 08.06.2010
size_t
равен sizeof(size_t)
. Стандарт C гарантирует, что SIZE_MAX
будет не менее 65535. size_t
- это тип, возвращаемый оператором sizeof
, и используется в стандартной библиотеке (например, strlen
возвращает size_t
). Как сказал Брендан, size_t
не обязательно должно совпадать с unsigned int
.
- person Alok Singhal; 09.06.2010
size_t
- это не то же самое, что unsigned int
, я думаю, вы имеете в виду, что не гарантируется, что это будет int
, хотя на самом деле это unsigned
. Это правда?
- person Lazer; 13.06.2010
size_t
гарантированно беззнаковый тип.
- person Alok Singhal; 13.06.2010
s1
и s2
имеют беззнаковый тип (например, size_t
), результат s1-s2
не может быть отрицательным, даже если s1 < s2
. Это потому, что беззнаковые типы не имеют отрицательных значений. Когда вы присваиваете эту разницу int
, результат определяется реализацией. В этом и заключалась вся суть в том, чтобы сказать, что никто не хочет принимать во внимание различие беззнаковых типов в моем примере, потому что нужно иметь возможность переносимо получить возможную отрицательную разницу.
- person Alok Singhal; 14.06.2011
size_t s2 = 5, s1 = 20; int diff = s2 - s1; printf("%d: %x\n", diff, diff < 0);
Это напечатает именно то, что вы ожидаете: "-15: 1"
- person Jason Oster; 02.07.2015
s2 - s1
превышает int
, поведение не определено.
- person Alok Singhal; 06.07.2015
size_t
- это тип, который может содержать любой индекс массива.
В зависимости от реализации это может быть любое из:
unsigned char
unsigned short
unsigned int
unsigned long
unsigned long long
Вот как size_t
определяется в stddef.h
моей машины:
typedef unsigned long size_t;
typedef unsigned long size_t
зависит от компилятора. Или вы предполагаете, что это всегда так?
- person chux - Reinstate Monica; 31.10.2014
unsigned long
- 32-битный, size_t
- 64-битный.
- person Tim Čas; 29.12.2014
size_t
не является переменной. Это тип, который вы можете использовать, когда хотите представить размер объекта в памяти.
- person Arjun Sreedharan; 01.08.2016
size_t
всегда 32 бита на 32-битной машине, 64 бита тоже?
- person John Wu; 24.08.2016
unsigned char
?
- person jameshfisher; 30.11.2016
uint_least16_t
- это как минимум 16 бит. О, size_t
, стандарт говорит беззнаковый целочисленный тип результата оператора sizeof, а оператор sizeof дает размер (в байтах) его операнда.
- person Arjun Sreedharan; 30.11.2016
unsigned char
не может быть 16-битным ?!
- person Antti Haapala; 16.10.2017
unsigned char
содержит хотя бы значения 0-255
.
- person jameshfisher; 16.10.2017
Если вы эмпирический тип,
echo | gcc -E -xc -include 'stddef.h' - | grep size_t
Вывод для 64-разрядной версии Ubuntu 14.04 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? а>
size_t
, по крайней мере, в популярном дистрибутиве Linux.
- person Andrey Portnoy; 11.01.2019
На странице руководства для types.h говорится:
size_t должен быть беззнаковым целочисленным типом
Поскольку никто еще не упомянул об этом, основное лингвистическое значение size_t
состоит в том, что оператор sizeof
возвращает значение этого типа. Точно так же основное значение ptrdiff_t
состоит в том, что вычитание одного указателя из другого даст значение этого типа. Библиотечные функции, которые его принимают, делают это, потому что это позволит таким функциям работать с объектами, размер которых превышает UINT_MAX в системах, где такие объекты могут существовать, не заставляя вызывающих абонентов тратить впустую код, передавая значение больше, чем "unsigned int" в системах, где тип большего размера хватило бы для всех возможных объектов.
malloc()
. Лично мне хотелось бы видеть версии, которые принимают аргументы типа int
, long
и long long
, при этом некоторые реализации продвигают более короткие типы, а другие реализуют, например, lmalloc(long n) {return (n < 0 || n > 32767) ? 0 : imalloc(n);}
[на некоторых платформах вызов imalloc(123)
был бы дешевле, чем вызов lmalloc(123);
, и даже на платформе, где size_t
составляет 16 бит, код, который хочет выделить размер, вычисленный в значении `long` ...
- person supercat; 01.05.2019
Чтобы понять, почему size_t
должен был существовать и как мы сюда попали:
С практической точки зрения, size_t
и ptrdiff_t
гарантированно будут иметь ширину 64 бита в 64-битной реализации, 32 бита в 32-битной реализации и так далее. Они не могли заставить любой существующий тип означать это на каждом компиляторе, не нарушая унаследованный код.
size_t
или ptrdiff_t
не обязательно то же самое, что intptr_t
или uintptr_t
. Они различались на некоторых архитектурах, которые все еще использовались, когда size_t
и ptrdiff_t
были добавлены в Стандарт в конце 1980-х, и устарели, когда C99 добавил много новых типов, но еще не исчез (например, 16-битная Windows). X86 в 16-битном защищенном режиме имел сегментированную память, где максимально возможный массив или структура могли иметь размер всего 65 536 байт, но указатель far
должен был иметь ширину 32 бита, шире, чем регистры. В них intptr_t
будет иметь ширину 32 бита, но size_t
и ptrdiff_t
могут быть шириной 16 бит и помещаться в регистр. И кто знал, что за операционная система может быть написана в будущем? Теоретически архитектура i386 предлагает 32-битную модель сегментации с 48-битными указателями, которую фактически никогда не использовала ни одна операционная система.
Тип смещения памяти не может быть long
, потому что слишком много унаследованного кода предполагает, что long
имеет ширину ровно 32 бита. Это предположение было даже встроено в API UNIX и Windows. К сожалению, многие другие унаследованные коды также предполагали, что long
достаточно широк, чтобы содержать указатель, смещение файла, количество секунд, прошедших с 1970 года, и так далее. POSIX теперь предоставляет стандартизированный способ заставить последнее предположение быть истинным вместо первого, но ни то, ни другое не является переносимым предположением.
Это не могло быть int
, потому что лишь небольшая горстка компиляторов в 90-е имела int
64-битную ширину. Потом они действительно стали странными, сохранив ширину long
32 бита. В следующей редакции Стандарта было объявлено незаконным, чтобы int
был шире, чем long
, но int
по-прежнему имеет ширину 32 бита в большинстве 64-битных систем.
Это не могло быть long long int
, который в любом случае был добавлен позже, поскольку он был создан с шириной не менее 64 бит даже в 32-битных системах.
Итак, понадобился новый тип. Даже если бы это было не так, все эти другие типы означали нечто иное, чем смещение в массиве или объекте. И если и был один урок из фиаско миграции с 32 на 64-разрядную версию, то он должен был быть конкретным в отношении того, какие свойства должен иметь тип, а не использовать одно, которое означало разные вещи в разных программах.
size_t
и ptrdiff_t
гарантированно будет иметь ширину 64 бита в 64-битной реализации и т. Д. гарантия завышена. Диапазон size_t
в первую очередь определяется объемом памяти реализации. n-битная реализация - это, прежде всего, собственная ширина процессора целых чисел. Конечно, многие реализации используют память одинакового размера и ширину шины процессора, но существуют широкие собственные целые числа со скудной памятью или узкие процессоры с большим объемом памяти, которые разделяют эти два свойства реализации.
- person chux - Reinstate Monica; 24.01.2020
size_t
и int
не взаимозаменяемы. Например, в 64-битной Linux size_t
имеет размер 64-бит (т.е. sizeof(void*)
), а int
- 32-битный.
Также обратите внимание, что size_t
беззнаковый. Если вам нужна подписанная версия, то на некоторых платформах есть ssize_t
, и это будет более актуально для вашего примера.
Как правило, я предлагаю использовать int
для большинства общих случаев и использовать _9 _ / _ 10_ только тогда, когда в этом есть особая необходимость (например, с mmap()
).
size_t
- это целочисленный тип данных без знака, который может присваивать только 0 и более 0 целочисленных значений. Он измеряет байты любого размера объекта и возвращается оператором sizeof
.
const
- это синтаксическое представление size_t
, но без const
вы можете запустить программу.
const size_t number;
size_t
регулярно используется для индексации массивов и подсчета циклов. Если компилятор 32-bit
, он будет работать с unsigned int
. Если компилятор 64-bit
, он также будет работать с unsigned long long int
. Максимальный размер size_t
в зависимости от типа компилятора.
size_t
уже определен в <stdio.h>
заголовочном файле, но он также может быть определен заголовками <stddef.h>
, <stdlib.h>
, <string.h>
, <time.h>
и <wchar.h>
.
const
)#include <stdio.h>
int main()
{
const size_t value = 200;
size_t i;
int arr[value];
for (i = 0 ; i < value ; ++i)
{
arr[i] = i;
}
size_t size = sizeof(arr);
printf("size = %zu\n", size);
}
Вывод: size = 800
const
)#include <stdio.h>
int main()
{
size_t value = 200;
size_t i;
int arr[value];
for (i = 0; i < value; ++i)
{
arr[i] = i;
}
size_t size = sizeof(arr);
printf("size = %zu\n", size);
}
Вывод: size = 800
В общем, если вы начинаете с 0 и движетесь вверх, всегда используйте беззнаковый тип, чтобы избежать переполнения, которое приведет вас к ситуации с отрицательным значением. Это критически важно, потому что, если границы вашего массива оказываются меньше максимума вашего цикла, но ваш максимум цикла оказывается больше максимума вашего типа, вы обернетесь отрицательным, и вы можете столкнуться с ошибка сегментации (SIGSEGV). Итак, в общем, никогда не используйте int для цикла, начинающегося с 0 и идущего вверх. Используйте беззнаковый.
size_t - это целочисленный тип данных без знака. В системах, использующих библиотеку GNU C, это будет целое число без знака или длинное целое без знака. size_t обычно используется для индексации массивов и подсчета циклов.
size_t или любой беззнаковый тип можно рассматривать как переменную цикла, поскольку переменные цикла обычно больше или равны 0.
Когда мы используем объект size_t, мы должны убедиться, что во всех контекстах, в которых он используется, включая арифметику, нам нужны только неотрицательные значения. Например, следующая программа обязательно даст неожиданный результат:
// 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
Это зависит от платформы typedef
. Например, на конкретной машине это может быть unsigned int
или unsigned long
. Вы должны использовать это определение для большей переносимости вашего кода.
Насколько я понимаю, size_t
- это unsigned
целое число, размер бит которого достаточно велик, чтобы содержать указатель на собственную архитектуру.
So:
sizeof(size_t) >= sizeof(void*)
size_t
. Несколько примеров: компиляторы C в реальном режиме x86 могут иметь 32-битные FAR
или HUGE
указатели, но size_t по-прежнему составляет 16 бит. Другой пример: Watcom C использовал специальный жирный указатель для расширенной памяти шириной 48 бит, а size_t
- нет. На встроенном контроллере с архитектурой Гарварда у вас тоже нет корреляции, потому что оба относятся к разным адресным пространствам.
- person Patrick Schlüter; 26.07.2013
size_t
- person Patrick Schlüter; 26.07.2013
int
, еслиsome_size
подписан,size_t
, если он не подписан. - person Nate   schedule 31.03.2010int i
может быть недостаточно для адресации огромного массива. Таким образом, используяsize_t i
, вы можете обращаться к большему количеству индексов, поэтому даже если у вас огромный массив, это не должно быть проблемой.size_t
- это тип данных: обычноunsigned long int
, но это зависит от вашей системы. - person bruno   schedule 14.02.2020