rusi/include/stdarg.h

145 lines
7.4 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// stdarg.h - Макросы для работы с переменным числом аргументов функций
//
// Этот заголовочный файл реализует механизм передачи переменного числа
// аргументов (variadic functions) согласно ABI System V для x86-64.
//
// Структура __va_state отражает внутреннее представление области
// сохранения регистров, создаваемой компилятором для variadic функций.
//
// Поддерживаются как стандартные макросы (va_start, va_arg, va_end, va_copy),
// так и русские синонимы (аргачало, арг_взять, аргонец, аргопия).
#ifndef _STDARG_H_RU
#define _STDARG_H_RU
// ============================================================
// Внутреннее состояние списка аргументов
// ============================================================
// Структура описывает состояние итератора по аргументам variadic функции.
// Она отражает ABI x86-64 System V:
// - gp_offset: смещение в области сохранения регистров общего назначения
// - fp_offset: смещение в области сохранения регистров с плавающей точкой
// - overflow_arg_area: указатель на аргументы, переданные через стек
// - reg_save_area: указатель на область сохранения регистров
typedef struct {
unsigned int gp_offset;
unsigned int fp_offset;
void *overflow_arg_area;
void *reg_save_area;
} __va_state;
// Список аргументов — массив из одного элемента __va_state.
// Такое представление позволяет передавать список по ссылке
// и модифицировать его внутри функций.
typedef __va_state va_list[1];
// ============================================================
// Инициализация и завершение работы с аргументами
// ============================================================
// Инициализация списка аргументов.
// Копирует состояние из специальной области __va_area__,
// которая создаётся компилятором для каждой variadic функции.
#define va_start(ap, last) \
do { *(ap) = *(__va_state *)__va_area__; } while (0)
// Завершение работы со списком аргументов.
// В данной реализации не требует никаких действий.
#define va_end(ap)
// ============================================================
// Внутренние функции извлечения аргументов
// ============================================================
// Извлечение аргумента из области переполнения (переданного через стек).
// Выравнивает указатель согласно требованиям типа и продвигает
// область переполнения вперёд с учётом размера и выравнивания.
static void *__va_read_from_stack(__va_state *ap, int sz, int align) {
void *p = ap->overflow_arg_area;
if (align > 8)
p = (p + 15) / 16 * 16;
ap->overflow_arg_area = ((unsigned long)p + sz + 7) / 8 * 8;
return p;
}
// Извлечение аргумента из области сохранения регистров общего назначения.
// Если регистры общего назначения исчерпаны (gp_offset >= 48),
// переключается на извлечение из стека.
static void *__va_read_from_gp(__va_state *ap, int sz, int align) {
if (ap->gp_offset >= 48)
return __va_read_from_stack(ap, sz, align);
void *r = ap->reg_save_area + ap->gp_offset;
ap->gp_offset += 8;
return r;
}
// Извлечение аргумента из области сохранения регистров с плавающей точкой.
// Если регистры с плавающей точкой исчерпаны (fp_offset >= 112),
// переключается на извлечение из стека.
static void *__va_read_from_fp(__va_state *ap, int sz, int align) {
if (ap->fp_offset >= 112)
return __va_read_from_stack(ap, sz, align);
void *r = ap->reg_save_area + ap->fp_offset;
ap->fp_offset += 8;
return r;
}
// ============================================================
// Извлечение следующего аргумента
// ============================================================
// Извлечение следующего аргумента заданного типа из списка.
// Использует встроенную функцию __builtin_reg_class для определения
// класса регистра (0 - общего назначения, 1 - плавающая точка, 2 - память)
// и вызывает соответствующую функцию извлечения.
#define va_arg(ap, ty) \
({ \
int klass = __builtin_reg_class(ty); \
*(ty *)(klass == 0 ? __va_read_from_gp(ap, sizeof(ty), _Alignof(ty)) : \
klass == 1 ? __va_read_from_fp(ap, sizeof(ty), _Alignof(ty)) : \
__va_read_from_stack(ap, sizeof(ty), _Alignof(ty))); \
})
// ============================================================
// Копирование списка аргументов
// ============================================================
// Копирование состояния списка аргументов.
// Позволяет итерироваться по аргументам независимо в разных местах.
#define va_copy(dest, src) ((dest)[0] = (src)[0])
// ============================================================
// Совместимость с GCC
// ============================================================
// Макрос, указывающий, что va_list совместим с GCC
#define __GNUC_VA_LIST 1
// Альтернативное имя типа для совместимости с GCC
typedef va_list __gnuc_va_list;
// ============================================================
// Русские синонимы для удобства
// ============================================================
// Тип списка аргументов
#define аргументы va_list
// Инициализация списка аргументов
// Пример: аргачало(args, последний);
#define аргачало va_start
// Завершение работы со списком аргументов
#define аргонец va_end
// Извлечение следующего аргумента
// Пример: цел x = арг_взять(args, цел);
#define арг_взять va_arg
// Копирование списка аргументов
#define аргопия va_copy
#endif // _STDARG_H_RU