stddef.h
stddef.h — заголовочный файл стандартной библиотеки языка программирования С, определяющий макросы NULL и offsetof, а также типы ptrdiff_t, wchar_t и size_t.
Включение
[править | править код]Для использования заголовочного файла «stddef.h» в коде на языке C используется директива препроцессора:
#include <stddef.h>
Стандарт языка C++ определяет эквивалентный заголовочный файл «cstddef», подключаемый директивой:
#include <cstddef>
Пространство имён
[править | править код]Основное отличие «stddef.h» от «cstddef» заключается в том, что в «cstddef» определения типов размещены в пространстве имён std
. То есть, в C++ определены std::size_t
и std::ptrdiff_t
вместо size_t и ptrdiff_t.
NULL
[править | править код]Константа #define
препроцессора, обозначающая константный нулевой указатель и определённая одним из следующих способов (в зависимости от компилятора и языка).
#define NULL ((void*)0)
#define NULL 0
#define NULL 0L
offsetof(type, member)
[править | править код]Макрос препроцессора, определённый стандартом ANSI C и возвращающий значение типа size_t[1]. Макрос вычисляет смещение в байтах поля структуры или объединения от начала структуры или объединения[2].
Классическая реализация макроса работала с компиляторами, не проверяющими типы указателей, и основана на получении смещения поля структуры, размещёной в памяти по нулевому адресу:
#define offsetof( st, m ) ( (size_t) (& ((st *)0)->m ) )
Нулевой указатель преобразуется к указателю на структуру st. Затем оператор «&» получает адрес поля m указанной структуры.
Современные компиляторы реализуют макрос с помощью встроенных функций. Например, реализация gcc выглядит следующим образом[3]:
#define offsetof( st, m ) __builtin_offsetof( st, m )
Использование встроенной функции имеет несколько преимуществ. Например, для кода на C++ не вызывается перегруженный оператор «&»[4].
Макрос offsetof()
позволяет писать код, работающий с разными структурами данных (см. обобщённое программирование). Например, в коде ядра ОС Linux с помощью offsetof()
реализован макрос container_of()
, получающий указатель на структуру по указателю на её поле[5]:
#define container_of( ptr, type, member ) \
( \
{ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof( type, member ) ); \
} \
)
#include <stddef.h>
#include <stdio.h>
int main()
{
struct car
{
char brand[31];
char hp[30];
double price;
double tmp;
} t;
//смещение относительно начала.
printf("%lu\n", offsetof(struct car, brand));
printf("%lu\n", offsetof(struct car, hp));
printf("%lu\n", offsetof(struct car, price));
printf("%lu\n", offsetof(struct car, tmp));
printf("\n");
//размеры членов структуры
printf("%lu\n", sizeof (t.brand));
printf("%lu\n", sizeof (t.hp));
printf("%lu\n", sizeof (t.price));
printf("%lu\n", sizeof (t.tmp));
// размер занимаемый структурой в памяти.
printf("sizeof struct = %lu\n", sizeof(struct car));
}
В реализации используется оператор typeof()
[6], не описанный в стандарте языка C.
Пример использования макроса container_of()
.
struct my_struct {
const char * name;
struct list_node list;
};
extern struct list_node * list_next ( struct list_node * );
void example () {
struct list_node * current = /* ... */
while ( current != NULL ) {
struct my_struct * element = container_of( current, struct my_struct, list );
printf( "%s\n", element->name );
current = list_next( &element->list );
}
}
В примере перебираются элементы связного списка, по указателю на поле list вычисляется указатель на структуру my_struct.
Тип size_t
[править | править код]Тип size_t
беззнаковый, создан специально для хранения размера объектов любых типов и имеет достаточную для этого разрядность[7]. Разрядность зависит от платформы: на 32-битных платформах может составлять 32 бита, на 64-битных — 64 бита. Значения этого типа возвращают операторы sizeof()
, _Alignof()
и макрос offsetof. Максимальное значение равно SIZE_MAX
(константа #define
из файла «stdint.h»).
Стандарт POSIX определяет знаковый тип ssize_t
(файл «unistd.h» для ОС UNIX или файл «stddef.h» для GNU C). Тип ssize_t
является типом size_t
со знаком. Комментарий в файле «sys/types.h» гласит, что ssize_t
используется для подсчёта байт и выявления ошибок, может хранить значения по крайней мере от -1
до SSIZE_MAX
.
Тип wchar_t
[править | править код]Тип wchar_t
создан для хранения «широкого символа» (англ. wide character), определён в файлах «stddef.h» и «wchar.h». Разрядность «широкого символа» зависит от реализации компилятора.
Тип ptrdiff_t
[править | править код]Тип ptrdiff_t
создан для хранения разности между двумя указателями. Разрядность типа ptrdiff_t
зависит от платформы и реализации компилятора.
Ссылки
[править | править код]- ISO/IEC 9899:2011 Черновик стандарта C11 (англ.).
- Описание файла «stddef.h» в стандарте «Single UNIX specification 2».
- Описание файла «cstddef». CPlusPlus.com.
Примечания
[править | править код]- ↑ Макрос offsetof() Архивная копия от 19 декабря 2014 на Wayback Machine (англ.). cppreference.com
- ↑ offsetof reference . MSDN. Дата обращения: 19 сентября 2010. Архивировано 10 октября 2011 года.
- ↑ Описание макроса offsetof(). Документация gcc. gnu.org . Free Software Foundation. Дата обращения: 19 сентября 2010. Архивировано 24 июля 2010 года.
- ↑ What is the purpose and return type of the __builtin_offsetof operator? Дата обращения: 20 октября 2012. Архивировано 15 декабря 2014 года.
- ↑ Greg Kroah-Hartman (англ.). Макрос container_of() . Журнал «Linux Journal» (июнь 2003). Дата обращения: 19 сентября 2010. Архивировано 13 февраля 2010 года.
- ↑ Оператор typeof() Архивная копия от 9 мая 2022 на Wayback Machine. Документация gcc. gnu.org
- ↑ Тип size_t Архивная копия от 19 декабря 2014 на Wayback Machine. cppreference.com