// 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