crypt of decay - August 25th, 2013 [entries|archive|friends|userinfo]
ketmar

[ userinfo | ljr userinfo ]
[ archive | journal archive ]

August 25th, 2013

половые акты с препроцессором в необычных позах [Aug. 25th, 2013|10:54 am]
ПРЕДУПРЕЖДЕНИЕ: кто ходит в гости по утрам использует такой код — гад, скотина, мудак и долбоёб.

Итак. Есть у нас язык «C». Делаем мы на нём какую-то унылую ерунду, и хотим мы, чтобы конструктор некоторого объекта (пусть это будет «бесполезная точка») существовал в трёх вариантах: без аргументов, с одним аргументом и с двумя аргументами. Можно, конечно, каждый раз руками делать что-то типа point_new_empty(), point_new_x(x), point_new_xy(x, y). А можно сделать извращение и поабузить препроцессор. Вот так, например:

#define _X_VA_XARGS_IMPL(_1, _2, _3, _4, N, …) N
#define _X_VA_XARGS(…) _X_VA_XARGS_IMPL(__VA_ARGS__, _bad, _2a, _1a, _0a)

#define _X_POINT_NEW_IMPL2(_pfx,_sfx, …) _pfx ## _sfx (__VA_ARGS__)
#define _X_POINT_NEW_IMPL(_pfx,_sfx, …) _X_POINT_NEW_IMPL2(_pfx,_sfx, __VA_ARGS__)
#define point_new(…) _X_POINT_NEW_IMPL(point_new, _X_VA_XARGS(_nothing_, ##__VA_ARGS__), __VA_ARGS__)

#include <stdio.h>
#include <stdlib.h>

static void point_new_0a (void) { printf("point_new(undef, undef)\n"); }
static void point_new_1a (int n0) { printf("point_new(%d, undef)\n", n0); }
static void point_new_2a (int n0, int n1) { printf("point_new(%d, %d)\n", n0, n1); }

int main () {
point_new();
point_new(42);
point_new(42, 666);
return 0;
}


да-да-да, я знаю: извращенцы отаке. Но работает. Ах, да: учтите, что трюк «##__VA_ARGS__» — это специфичная для гнутого препроцессора фича. Без этой фичи отдетектить отсутствие аргументов тоже можно, но ебанётесь на отличненько.

Для тех, кто не врубился, отчего так дохуя макросов: специфика препроцессорной «развёртки», так надо. Читайте доки, они рулят. А кто не использует gcc — тот сам дурак и пусть сосёт бензин.
Link13 meows|meow!

navigation
[ viewing | August 25th, 2013 ]
[ go | Previous Day|Next Day ]