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