3 ms·
Very interesting also as a thought-provoking idea. For example - It would be less challenging if function pointers variables are used instead of function. In
by Agraillo 2y ago
Very interesting also as a thought-provoking idea. For example
- It would be less challenging if function pointers variables are used instead of function. In this case, the code appended later may override the function variables it needs to fix/change
- Since all the code is there, it is possible to invent some convention to compile/run previous versions without CVS machinery
- kragen 2y agoI'm not sure how you would override the function pointers repeatedly without getting a compile error. Maybe you could instead use functions with GCC's weak attribute?
- Agraillo 2y agoI see no issue in setting it dynamically from the code, supposed to be set during start-up code. A global variable representing a function pointer and this variable either changed several times (if the latest addition allows execution of previous routines then setting its new value) or just once for the latest version if the logic somehow disables previous start-up routines. Can be called "dynamic inheritance"
- kragen 2y agoHow do you change the global variable, though?
- Y_Y 2y agoI guess they mean to overwrite the pointers: void (*foo)(void) int main(){ *foo(); } void foo1(){...} foo = &foo1; // will be overwritten later void foo2(){...} foo = &foo2; I'm on my phone so I haven't compiled it, but that's the rough idea I got, define lots of versions and then set the version to the latest one. (You can skip the address-of for functions by punning, but reading the types is hard enough already.)
- kragen 2y agoThat's not valid C; you can't put statements outside of functions, not even assignment statements or other expression statements. No C compiler I've ever used will accept it. Where would the compiled version of those statements go, in an init function? Linkers added support for those for C++ static initializers, where execution order isn't defined; C doesn't have anything similar. Are you expecting the compiler to execute the assignment statements at compile time, with a C interpreter?
- Y_Y 2y ago(What's the language lawyer equivalent of an ambulance chaser?) Fair point, I hadn't thought it all the way through. It's also all too easy to assume you can use C++ features or GNU extensions if you're not in the habit of enforcing the standard. For your trouble here are two partial solutions: --- 1. CPP abuse If I was doing this myself I'd probably just use the preprocessor to make the last function my entry point like SOURCE=file.c gcc -DLATEST_MAIN=$(grep -E "^[a-zA-Z_].*\(.*\)\s*\{" ${SOURCE} | tail -1 | grep -Po "[a-zA-Z_]\w*(?=\()") ${SOURCE} and then you can start with int main(void){LATEST_MAIN();}; and append void foo(){...} ... void bar(){...} and execution will start from the last defined function (that matches the regex). --- 2. Pre-defining non-static functions If that's cheating then you can redefine "external" functions before the linker has a chance to provide them. For example: #include <stdlib.h> int (*foo)(void); int main(void){exit(0); *foo();} is a valid program, and you can append void f1(){puts("oh");} int exit(){foo=&f1;} and foo will indeed be called. It does require some forward planning if you want to append multiple times, but it shouldn't be so difficult to generate a library full of dummy functions to use.
- kragen 2y agoThis isn't a language-lawyer kind of thing, and, as I said, I don't think C++ features or GNU extensions will help. The pre-defining extern functions approach will get you a finite number of tries, but I suppose it could be a fairly large finite number. If for some reason I had to solve this problem in real life I would do it with a postprocesing step like your #1 suggestion. But once you're putting code into your Makefile anything goes.