$ 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!
Created
August 7, 2012 12:34
-
-
Save pasberth/3284943 to your computer and use it in GitHub Desktop.
setjmp で遊ぶ
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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