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.

Константа #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 беззнаковый, создан специально для хранения размера объектов любых типов и имеет достаточную для этого разрядность[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 создан для хранения «широкого символа» (англ. wide character), определён в файлах «stddef.h» и «wchar.h». Разрядность «широкого символа» зависит от реализации компилятора.

Тип ptrdiff_t создан для хранения разности между двумя указателями. Разрядность типа ptrdiff_t зависит от платформы и реализации компилятора.

Примечания

[править | править код]
  1. Макрос offsetof() Архивная копия от 19 декабря 2014 на Wayback Machine (англ.). cppreference.com
  2. offsetof reference. MSDN. Дата обращения: 19 сентября 2010. Архивировано 10 октября 2011 года.
  3. Описание макроса offsetof(). Документация gcc. gnu.org. Free Software Foundation. Дата обращения: 19 сентября 2010. Архивировано 24 июля 2010 года.
  4. What is the purpose and return type of the __builtin_offsetof operator? Дата обращения: 20 октября 2012. Архивировано 15 декабря 2014 года.
  5. Greg Kroah-Hartman (англ.). Макрос container_of(). Журнал «Linux Journal» (июнь 2003). Дата обращения: 19 сентября 2010. Архивировано 13 февраля 2010 года.
  6. Оператор typeof() Архивная копия от 9 мая 2022 на Wayback Machine. Документация gcc. gnu.org
  7. Тип size_t Архивная копия от 19 декабря 2014 на Wayback Machine. cppreference.com