Skip to content

Instantly share code, notes, and snippets.

@pasberth
Created August 7, 2012 12:34
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pasberth/3284943 to your computer and use it in GitHub Desktop.
Save pasberth/3284943 to your computer and use it in GitHub Desktop.
setjmp で遊ぶ
$ clang -v

clang version 3.0 (tags/RELEASE_30/final)
Target: i386-pc-linux-gnu
Thread model: posix

$ clang lambda_macro.c
$ ./a.out

lambda defined.
call lambda!
lambda called.
1 times called. str = hello
return lambda!
call lambda!
lambda called.
2 times called. str = world
return lambda!
lambda defined.
call lambda!
lambda called.
hoge
return lambda!
call lambda!
lambda called.
fuga
return lambda!
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <setjmp.h>
typedef struct lambda {
jmp_buf lambda_location;
jmp_buf return_location;
void **args;
} lambda;
#define LAMBDA_ARGC_MAX 256
#define LAMBDA_ARGS_NEW(ptr, ...) \
{ \
void *__lambda_args_tmp[LAMBDA_ARGC_MAX] = { __VA_ARGS__ }; \
ptr->args = calloc(LAMBDA_ARGC_MAX, sizeof(void *)); \
memcpy(ptr->args, __lambda_args_tmp, LAMBDA_ARGC_MAX); \
}
#define LAMBDA_ARGS_FREE(ptr) \
{ \
if (ptr && ptr->args) free(ptr->args); \
}
/*
* LAMBDA_CALL(lambda_ptr, arg1, arg2 .. argN);
*/
#define LAMBDA_CALL(ptr, ...) \
{ \
if (setjmp(ptr->return_location) == 0) { \
puts("call lambda!"); \
LAMBDA_ARGS_NEW(ptr, __VA_ARGS__); \
longjmp(ptr->lambda_location, 1); \
} else { \
puts("return lambda!"); \
LAMBDA_ARGS_FREE(ptr); \
} \
}
/*
* LAMBDA(lambda_ptr,
* {
* // Some code.
* });
*/
#define LAMBDA(ptr, body) \
{ \
if (setjmp(ptr->lambda_location) == 0) { \
/* ラムダ定義時はなにもしない */ \
puts("lambda defined."); \
} else { \
/* LAMBDA_CALL() によって呼ばれたとき */ \
puts("lambda called."); \
body; \
longjmp(ptr->return_location, 1); \
} \
}
void example1()
{
lambda l;
lambda *lp = &l;
int count = 0;
LAMBDA( lp,
{
count++;
char *str = lp->args[0];
printf("%d times called. str = %s\n", count, str);
});
LAMBDA_CALL(lp, "hello");
LAMBDA_CALL(lp, "world");
}
lambda *example2_defines_lambda_in_a_function()
{
lambda *lp = malloc(sizeof(lambda));
/* 変数の宣言とか参照はかなり危うい。
* int count = 42;
*/
LAMBDA( lp, {
puts(lp->args[0]); // 変数を受け取ったりはできるが…
/* たぶんセグフォが落ちであろう。
* char *str = "Segumentation fault";
* printf("%d times called. str = %s\n", count, str);
*/
});
return lp;
}
void example2()
{
lambda *l = example2_defines_lambda_in_a_function();
LAMBDA_CALL(l, "hoge");
LAMBDA_CALL(l, "fuga");
}
int main(int argc, char *argv[])
{
example1();
example2();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment