_info (4415B)
1 #include "config.h" 2 #include <stdio.h> 3 #include <string.h> 4 5 /** 6 * typesafe_cb - macros for safe callbacks. 7 * 8 * The basis of the typesafe_cb header is typesafe_cb_cast(): a 9 * conditional cast macro. If an expression exactly matches a given 10 * type, it is cast to the target type, otherwise it is left alone. 11 * 12 * This allows us to create functions which take a small number of 13 * specific types, rather than being forced to use a void *. In 14 * particular, it is useful for creating typesafe callbacks as the 15 * helpers typesafe_cb(), typesafe_cb_preargs() and 16 * typesafe_cb_postargs() demonstrate. 17 * 18 * The standard way of passing arguments to callback functions in C is 19 * to use a void pointer, which the callback then casts back to the 20 * expected type. This unfortunately subverts the type checking the 21 * compiler would perform if it were a direct call. Here's an example: 22 * 23 * static void my_callback(void *_obj) 24 * { 25 * struct obj *obj = _obj; 26 * ... 27 * } 28 * ... 29 * register_callback(my_callback, &my_obj); 30 * 31 * If we wanted to use the natural type for my_callback (ie. "void 32 * my_callback(struct obj *obj)"), we could make register_callback() 33 * take a void * as its first argument, but this would subvert all 34 * type checking. We really want register_callback() to accept only 35 * the exactly correct function type to match the argument, or a 36 * function which takes a void *. 37 * 38 * This is where typesafe_cb() comes in: it uses typesafe_cb_cast() to 39 * cast the callback function if it matches the argument type: 40 * 41 * void _register_callback(void (*cb)(void *arg), void *arg); 42 * #define register_callback(cb, arg) \ 43 * _register_callback(typesafe_cb(void, void *, (cb), (arg)), \ 44 * (arg)) 45 * 46 * On compilers which don't support the extensions required 47 * typesafe_cb_cast() and friend become an unconditional cast, so your 48 * code will compile but you won't get type checking. 49 * 50 * Example: 51 * #include <ccan/typesafe_cb/typesafe_cb.h> 52 * #include <stdlib.h> 53 * #include <stdio.h> 54 * 55 * // Generic callback infrastructure. 56 * struct callback { 57 * struct callback *next; 58 * int value; 59 * int (*callback)(int value, void *arg); 60 * void *arg; 61 * }; 62 * static struct callback *callbacks; 63 * 64 * static void _register_callback(int value, int (*cb)(int, void *), 65 * void *arg) 66 * { 67 * struct callback *new = malloc(sizeof(*new)); 68 * new->next = callbacks; 69 * new->value = value; 70 * new->callback = cb; 71 * new->arg = arg; 72 * callbacks = new; 73 * } 74 * #define register_callback(value, cb, arg) \ 75 * _register_callback(value, \ 76 * typesafe_cb_preargs(int, void *, \ 77 * (cb), (arg), int),\ 78 * (arg)) 79 * 80 * static struct callback *find_callback(int value) 81 * { 82 * struct callback *i; 83 * 84 * for (i = callbacks; i; i = i->next) 85 * if (i->value == value) 86 * return i; 87 * return NULL; 88 * } 89 * 90 * // Define several silly callbacks. Note they don't use void *! 91 * #define DEF_CALLBACK(name, op) \ 92 * static int name(int val, int *arg) \ 93 * { \ 94 * printf("%s", #op); \ 95 * return val op *arg; \ 96 * } 97 * DEF_CALLBACK(multiply, *); 98 * DEF_CALLBACK(add, +); 99 * DEF_CALLBACK(divide, /); 100 * DEF_CALLBACK(sub, -); 101 * DEF_CALLBACK(or, |); 102 * DEF_CALLBACK(and, &); 103 * DEF_CALLBACK(xor, ^); 104 * DEF_CALLBACK(assign, =); 105 * 106 * // Silly game to find the longest chain of values. 107 * int main(int argc, char *argv[]) 108 * { 109 * int i, run = 1, num = argc > 1 ? atoi(argv[1]) : 0; 110 * 111 * for (i = 1; i < 1024;) { 112 * // Since run is an int, compiler checks "add" does too. 113 * register_callback(i++, add, &run); 114 * register_callback(i++, divide, &run); 115 * register_callback(i++, sub, &run); 116 * register_callback(i++, multiply, &run); 117 * register_callback(i++, or, &run); 118 * register_callback(i++, and, &run); 119 * register_callback(i++, xor, &run); 120 * register_callback(i++, assign, &run); 121 * } 122 * 123 * printf("%i ", num); 124 * while (run < 56) { 125 * struct callback *cb = find_callback(num % i); 126 * if (!cb) { 127 * printf("-> STOP\n"); 128 * return 1; 129 * } 130 * num = cb->callback(num, cb->arg); 131 * printf("->%i ", num); 132 * run++; 133 * } 134 * printf("-> Winner!\n"); 135 * return 0; 136 * } 137 * 138 * License: CC0 (Public domain) 139 * Author: Rusty Russell <rusty@rustcorp.com.au> 140 */ 141 int main(int argc, char *argv[]) 142 { 143 if (argc != 2) 144 return 1; 145 146 if (strcmp(argv[1], "depends") == 0) { 147 return 0; 148 } 149 150 return 1; 151 }