the versatility of c and how low level everything is really makes it fun to tinker with!
@JacobSorber
3 жыл бұрын
Definitely.
@junbird
3 жыл бұрын
I had this "object oriented C" phase a couple of years ago, a bit after starting university. I tried to implement as many features from higher level languages that I could in C, so classes, inheritence, overriding, polymorphism, etc. It was terrible, but it was also a great learning experience that made me discover many details about the C language and kinda how OO languages work under the hood. I also tried to implement exceptions of course, and I did it basically how it's shown in the video, but using even more macro magic (which of course is not a good idea, as pointed out in the video) and using the return value of setjmp in order to return an address to an exception object (I even tested at runtime that it was an instance of the "Exception" class requested by one of the catch block). Not something I'd recommend anyone actually using (mainly because C is not meant to be used like that), but again, it was fun.
@rkkm67
2 жыл бұрын
How did you learn to do all that? Is there a tutorial one can follow or any book?
@alec7987
Жыл бұрын
@@rkkm67 I did something like it as well. You do lots of Googling. I found all sorts of small posts all over the internet that helped me get it working. I even wrote a somewhat usable transpiler that can convert a vaguely C++ like class declaration into a header and source files that can be included.
@laughingvampire7555
Жыл бұрын
google for the "compiler design in c" book by Allen I Holub, is an old book, you can download the copy and shows you how to do just that in C. by the way, I wouldn't call OO higher level than C, is just an organization scheme of code around single dispatch, not higher level.
@paulk314
3 жыл бұрын
Are you familiar with the book "C Interfaces and Implementations"? One of the early chapters does what you did here, using the C preprocessor to implement try-catch-throw, but adds a stack to it allowing for multiple levels of exception handling, as well as some other niceties. Nice video!
@JacobSorber
3 жыл бұрын
Cool, I've seen the book, but apparently need to look more closely. Thanks.
@paulk314
3 жыл бұрын
@@user-io4sr7vg1v actually, yes. I wanted to read the whole thing but I only got a few chapters in and my brain needed a long break 🤣
@rallokkcaz
2 жыл бұрын
It's chapter 4 to be exact, I'm reading it right now. Wish me luck haha.
@diceandbricks
3 жыл бұрын
One important issue to keep in mind is proper use of volatile keyword for any local var that's modified after the setjmp.
@an0nsaiko890
3 жыл бұрын
I love C but sometimes find it somewhat lackluster, but these videos show some very neat features from other languages that you can emulate. Great stuff.
@dannyhunn6025
3 жыл бұрын
In college I was always taught to handle exceptions with goto, enum, a boiler plate, and 2 bit fields ( just two uint64_t). when an exception happens you set 2 bits in the bit fields ( one for location and one for the exception) then goto your exception handling area, each bit corresponds to an enum( for read abilty) in your boiler plate and loop through the bits with a a switch print where it happened and the exception. It also gives the chance to recover from the exception. Isn't setjmp a non local goto anyway?
@brycemw
3 жыл бұрын
If you really wanted to do something crazy, you could have it so that when you “try”, you first allocate a temporary variable and use that to store the old jmp_buf before saving the new state. Then you restore it after. If you did it right then it should be possible to do nested tries without adding more globals. You would probably want to make the global thread-local as well. This is really interesting so I might try making my own version at some point for fun!
@godnyx117
3 жыл бұрын
Best programming channel in YT!!!! Thanks cannot express how much I appreciate what you do for us! I truly wish you the best!
@JacobSorber
3 жыл бұрын
Thanks! It's always good to hear that the channel is making a difference. Thanks for the support.
@bluehornet6752
3 жыл бұрын
Somewhere, right now, Bjarne Stroustrup is clutching his chest and is about to lose consciousness. That said, I thought it was a damned cool video!
@botbeamer
3 жыл бұрын
xD
@axalius572
3 жыл бұрын
no classes: structs and functions no exceptions: error codes no stl: write your own code simple
@TheCocoaDaddy
3 жыл бұрын
This was pretty much how I started my programming career! lol
@SirRebonack
3 жыл бұрын
no namespaces
@axalius572
3 жыл бұрын
@@SirRebonack Namespace_Function
@zofe
3 жыл бұрын
Hiding the complexity by means of ignoring it, really?
@glumfish6862
3 жыл бұрын
@@zofe C doesn't hide any complexity. You have all the power in your hands, sometimes too much.
@ashgoku6966
3 жыл бұрын
My mind's blown . I never thought we could use preprocessed directives this way . Your channel never fails to suprise me , keep up the good work
@unperrier5998
2 жыл бұрын
The use of "exception_value" (global variable) can be avoided by using "switch/case" statements instead of "if/then".
@theglowingone5643
3 жыл бұрын
I remember trying to create exceptions in C a few months ago and I wish I would have seen this video before. I have currently another project but after that I want to try to implement asyncio (asynchronous IO) and I was wondering if one could do it using setcontext() and getcontext(). Can you make a video on that if you find the time? Thanks for your videos, they really keep me motivated to keep programming as I learn a lot from them.
@JacobSorber
3 жыл бұрын
You're welcome. Glad they're helpful. And, sure, I could probably do that. setcontext/getcontext and of course makecontext/swapcontext are a lot of fun. I'll see what I can put together.
@TheCocoaDaddy
3 жыл бұрын
Neat video!!!! I've never used setjmp and longjmp and I found your use of them clever to implement try/catch. :) Thanks for posting!
@unperrier5998
2 жыл бұрын
setjmp/longjmp a're typically used to restart a program. This is how a service restarts without losing its connections for instance or how configuration reload can be implemented.
@cernejr
3 жыл бұрын
BTW, the best piece of c++ code that I have worked on, a speech recognition engine developed over decades by very smart people, did not use exceptions, it just returned error codes when needed.
@JacobSorber
3 жыл бұрын
A great deal of exceptional code has been written without exception handling. Few things in programming are one-size-fits-all.
@Kotesu
3 жыл бұрын
Yes, that sounds familiar. What you are describing was considered best practice by several of my mentors when I was starting in embedded systems. Typically, every function returned a result code which was an enumerated integer, the values were encoded (bitpacked) to have a module ID and error ID in a single number and 0 was reserved for success. That way in a deep cal stack you could tell which module was causing problems by merely returning any error code you received. I still prefer this over complicated try..catch blocks as it is simpler and more consistent with normal execution flow (no sudden jumps up the call stack when you have several nested blocks).
@OmarRampado87
3 жыл бұрын
Like the goto statement, I use longjmp with care. To check the return of setjmp I use the switch statement and the case for each error. The errors are enum. Thank for sharing this interesting alternative!
@JacobSorber
3 жыл бұрын
You're welcome...and absolutely right about using care. Anytime you are jumping around, there's cause for concern. Opportunities to mess things up abound. 😀
@rdwells
3 жыл бұрын
One advantage of C++ exceptions is that they clean up objects as the stack unwinds, which longjmp can't do. Unfortunately, this also results in one of the disadvantages: the time it takes to handle an exception is (effectively) non-deterministic, so they shouldn't be used in hard real-time code. Still, they're one of the things that would make it really difficult for me to go back to use C (the other being the STL).
@astromec6303
7 ай бұрын
Well this point of whether or not exceptions should be used can be argued. Because u will have to clean up resources yourself anyways without exceptions so it’s basically the same. And in real time critical applications it could actually be very important to do so as it may not necessarily behave the same way as typically. E.g. in an embedded system u may not necessarily get a segmentation fault or the resources may not actually be reclaimed after program exit like in a modern OS.
@ls_hower
Жыл бұрын
Finally I've understood their usage, thx!
@doowi1182
3 жыл бұрын
This channel is incredible. Keep up the good work!
@user-jx8uz6tb6k
3 жыл бұрын
Thanks for existing!
@AlexSmith-jj9ul
Жыл бұрын
For what you are trying to do you don't even need to use setjmp or longjmp a function of the form: void throw(char * exception) { printf("Uncaught exception: %s ", exception);//or print to standard error whatever you perfer exit(1); return; } Will do just fine and exit properly.
@rafalmichalski4893
3 жыл бұрын
Great video Jacob !!! Once I did mechanism but based on single pass do-while loop and "break" (no goto at least) was acting as "throw" (more or less like "try" but without real "catch")
@iuppiterzeus9663
3 жыл бұрын
I'm in "the C world" for like half a year now and did not know this was a thing. Nice, thank you !
@szarinmehr
2 жыл бұрын
Hi Jacob I work for a company that has a huge code base of C and C++ generated over 40 years. We use the same mechanism to catch exceptions for both c and c++ in our implementation layer. This is indeed very smart. The only down-side of it in c++ is that longjump will not rewind the stack. For example, if you have a c++ std::vector object on the stack with hidden heap allocation its destructor will never be called and it will leak memory. I know you prefer c over c++ and I admire your reasons, but exception handling which may come with a tiny cost in c++ is where c++ really shines. Thanks for your wonderful tutorials!
@HansBezemer
3 жыл бұрын
Nice going! I used that one before, but I learned something never the less!
@peterSobieraj
6 ай бұрын
My first reaction was "this is crazy". But then at end of video I kind of get use to setjmp. I think I will stick with setjmp, and not create any defines for it. I like it. I think that for programmers "pretty" is just something that they are use to.
@victorlacerda9659
3 жыл бұрын
This was one of most elucidative explanation that i had have. Thanks You very much !!! :)
@MikkoRantalainen
2 ай бұрын
4:45 The only sane way to do this is to require pointer to jmp_buf as an argument to the function that wants to potentially "throw". That way you don't need function return site specific global variables to implement this. So instead of signature compute(avg, values, length) you would have signature compute(throw_buf, values, length).
@joshermar
3 жыл бұрын
Awesome and enjoyable as usual! Please consider doing a video on goto statements and their potential uses. Cheers.
@AnubhavApurva
2 жыл бұрын
Thanks a lot good explanation!
@SaiMouli034
2 ай бұрын
Nice explanation
@Sayan_Shankhari
3 ай бұрын
8:36 just define or use enums for different different possible error types
@unperrier5998
2 жыл бұрын
A big warning that you could have hightlighted is that "savebuf" can not and must not be used outside of the function where it has been initialized (where we call setjmp) because of the black magic longjmp() does with the stack. In a nutshell, as soon as we exit the function that calls setjmp(), savebuf becomes invalid because it contains reference(s) to a stack frame that doesn't exist any longer. Experienced programmers can workaround this limitation by using a different yet compatible stack frame, but it's libC implementation and compiler dependent, hence dangerous.
@JacobSorber
2 жыл бұрын
Good point. Thanks for mentioning that.
@rogo7330
7 ай бұрын
Nice thing about this is that setjump and longjump are defined in libc by POSIX and pretty much since C89 (that's what manpage said), so your code should work just fine across most of the compilers and systems. Just interesting how bad it is for CPU cache and compiler optimizations in general and what other caveats that will have, but this is like working with signal handlers (across all languages, by the way), pretty low level and needs you to understand what you can and should not do in them.
@Maklaka
2 жыл бұрын
If you wanted to next these, you would need to add an array of jmp_bufs and more defines like END_CATCH and END_TRY to be used at the bottom of those scopes to decrement the index into it once you are done with it.
@renhaoxue5220
2 жыл бұрын
Thanks! Good stuff
@bart2019
2 жыл бұрын
To make the try nestable your savebuf should be like a stack. After the try/catch blocks are executed, an item should be popped from the stack, or the next throw would put you back there - not only not doing the right thing, but possibly causing a crash.
@tordjarv3802
3 жыл бұрын
I think that this example really illustrates that try-catch style exception (also known as Structured Exeception Handling (SEH)) is just like goto, but way worse since it allows you to jump to a completely different part of the program and not just within the same method. Personally I prefer the style of exception handling that Rust uses, by exploiting monadic function calls where exception information is backed in to the return type and it is transparent that things could go wrong. But I do think that this was a really interesting video
@ic6406
8 ай бұрын
Some info about internal state would be fine to add into the video. For example, does this jump pop stack correctly, in other words, is stack pointer back to its position prior to the call to this average function
@eliavrad2845
3 жыл бұрын
Is there an equivalent to Generators in c? It sounds like a neat and interesting way to refactor complicated, nested looping logic over simple functions: would it have problem like slowness? I thought of this because had to print results, and had repeated sections of for (...) { ...complex, nested looping logic for getting each element ...; fprintf("field1: %d", element->field1); } which I guess could be done with macros, but would be nice to refactor to some generator function for (init();done();next()) { fprintf("field1: %d", element->field1); }
@rishabhanand4270
3 жыл бұрын
How about the finally block? Great vid btw.
@neerajkale
3 жыл бұрын
This is awesome! Thank you.
@JacobSorber
3 жыл бұрын
You're very welcome.
@anon_y_mousse
2 жыл бұрын
This is pretty close to how I handled the same thing, except I incorporated the current line number to allow multiple states with each nested level. Granted, it'll fail if some dingus puts everything on one line, but since I'm the only one using it it's okay. Though it was definitely easier than actually implementing setjmp and longjmp for my own libc. Now that I've been using RPi's for a while I may go back and add a version for ARM as well, perhaps revisit the idea of extending C just for fun and allow one liners that use it.
@michaelkotthaus7120
3 жыл бұрын
According to the MISRA guidelines from 2004, unions shall not be used (Rule 18.4). In the 2012 MISRA edition, this became only advisory (rule 19.2). Personally, I try to avoid unions. But there are some situations (also mentioned here in the comments), where an union is the only or the best solution. Related to your example, Jacob, a C++ programmer would probably advice to use polymorphic classes. In C, a union could be avoided by using pointers to structs which contain the "big" data (personality, firmware). Only one of these pointer must be unequal to 0. With this, you could also save the boolean flag which distinguishes between robot and human beeing. Nevertheless: Another great episode which helps me to think about data concepts. Thank you!
@cernejr
3 жыл бұрын
setjmp, longjmp - that is how c++ implements exceptions, doesn't it? I am not an expert.
@JacobSorber
3 жыл бұрын
I haven't looked under the hood with C++ to see if they actually call setjmp/longjmp, but yes they are using the same sort of mechanism.
@ailijic
3 жыл бұрын
It calls into the c++ run time but basically it is like setjmp/longjmp. You can attach a debugger to a c++ program and see what’s it doing, not for the faint of heart. The c++ compiler keeps track of all of the objects and calls their destructors, in reverse order, as it jumps up the stack.
@IIARROWS
2 жыл бұрын
I'm amused and terrified at the same time.
@malyarenko.m
3 жыл бұрын
But you haven't mentioned what happens to the stack frame of the function in which longjump was called. Is longjump going to pop the frame off the stack or some kind of memory leak will occure?
@wilfreddv
3 жыл бұрын
According to the man page longjmp transfers control to where setjmp was called, and restores the stack to the state it was in at the point where setjmp was called. Good eye for detail 🙂
@JacobSorber
3 жыл бұрын
Indeed. Good question. Yes, stack state and registers are restored.
@ailijic
3 жыл бұрын
It’s still C, you have to do your own memory management. If you are not careful you can have memory leaks, multiple initialization, double frees, and pointers pointing to bad data.
@taragnor
3 жыл бұрын
@@ailijic : Yeah, unlike C++ exceptions, it won't call destructors on objects when they go out of scope. You have to remember to do everything manually, which really does not scale well when you start to get into large projects.
@sudarshanv9797
3 жыл бұрын
For all windows users, if you want to try C in linux, try windows subsystem for linux (version 2), a subsystem available in windows, there are lot of videos and documentations about linux in windows, I am using it, I am having fun with linux along with windows
@Starwort
3 жыл бұрын
Why is this done with if-else instead of switch? Switch results in the (IMO slightly nicer): // jump_buffer can be removed and hardcoded if desired but this set of defines can be used for any code #define TRY(jump_buffer) switch(setjmp(jump_buffer)){case 0: #define CATCH(type) break; case type: #define CATCHALL break; default: #define ENDTRY } #define THROW(jump_buffer, type) longjmp(jump_buffer, type) TRY(savebuf) { // Code } CATCH(ENUMERATED_EXCEPTION) { // code } CATCHALL { // Generic } ENDTRY
@AshtonWolfwood
10 ай бұрын
To make this thread safe, do we need to pass the ’savebuf’ as parameter to the function?
@FelipeMendez
3 жыл бұрын
Does this work across libs? if I compile an exe and a dll does and the dll "throws" the exe catches it?
@JacobSorber
3 жыл бұрын
I haven't tried this on Windows. So, if by "DLL" you mean windows DLL, then I'm not sure. Try it out and let me know. If you're on a UNIX-based OS then yes you can jump from a library function into the calling process, as long as the library has access to the jmp_buf.
@ailijic
3 жыл бұрын
On most processors setjmp/longjmp just saves and restores all the registers. Would it work, yup. Will it do what you expect, maybe, probably not. You really want to limit the scope of setjmp/longjmp, e.g. use it in a library but return an error code to the consumer of the library. Setjmp/longjmp does nothing to manage memory.
@MithicSpirit
2 жыл бұрын
You could also have used switch case
@praenubilus1980
3 жыл бұрын
Want to see a discussion between exception handling vs error code. Cannot find some good discussion over the internet.
@botbeamer
3 жыл бұрын
Really interesting video
@helenmachelen4200
5 ай бұрын
Doesn't seem to catch system exceptions (null pointer etc)
@GeorgeTsiros
7 ай бұрын
i had almost forgotten about setjmp... dear god, no, why, why would you do this... is it even supported in long mode?
@muzafferirmakyavuz9993
3 жыл бұрын
Sir can u explain struct "constructor" using function pointers
@islandcave8738
3 жыл бұрын
You could use this to simulate generators with yield.
@brayancodes
3 жыл бұрын
That's why I love C! If you don't have something funny that other languages do, do it yourself xD. Great video. I learn a lot with your videos :)
@JacobSorber
3 жыл бұрын
Thanks. I'm glad you enjoyed it.
@gabrielcasanova7034
Жыл бұрын
is this the perfect use case for goto labels?
@kuaiyu977
3 жыл бұрын
I think python's try/catch will handle crashes like an out of bounds array index. Will setjump/longjump also handle that? If not it just feels like a wrapped goto statement.
@sababugs1125
3 жыл бұрын
Why not just use if else blocks ?
@weydans
3 жыл бұрын
Hi from Brazil! Some videos like it just make me ask: is there some thing impossible to implement on C Language? Congratulations for the amazing content!
@JacobSorber
3 жыл бұрын
Thanks! The theoretical answer is nearly always, yes you could do most anything in C, given enough time and effort. But, that time and effort component can be significant. 😀
@Alche_mist
3 жыл бұрын
There always is the halting problem...
@aaaowski7048
Жыл бұрын
btw, you cant catch a segfault. thats because its the OS that throws that. if i have been taught correctly, that is
@patrick_jane2164
3 жыл бұрын
Nice video and a cool idea! but you used an explicit throw statement, what happens if you divided for example? without a throw clause? Will it catch the exception?
@maxaafbackname5562
2 жыл бұрын
No, these are standard library functions, not a language construct.
@mayankpant1596
2 жыл бұрын
As a person who has been using Java almost all the time, the concept of not handling exceptions is so foreign to me that it took me years to learn c just because of that..
@diceandbricks
3 жыл бұрын
How would this work with multi threads? savebuff couldn't be global. Can you pass savebuff or *savebuff down the call stack as a parameter?
@nanda_8
2 жыл бұрын
I might sound stupid here... I have one question... Why not create a global variable itself (instead of setjmp, longjmp) and make it 1 when the condition satisfies(i.e exception) EDIT: I got it.
@JacobSorber
2 жыл бұрын
Not a stupid question at all, but I'm glad you figured it out. This topic and it's interesting control flow issues can take a little time to wrap our heads around.
@Fraket
3 жыл бұрын
Cool!
@mow3890
3 жыл бұрын
Great 👌
@gordonsau2989
3 жыл бұрын
After watching the video, I would like to know how often people do something like this. Is this how setjmp and longjmp are commonly used? Are the other languages with try catch blocks use something like setjmp and longjmp which save the stack pointer and other registers to implement the exception features?
@unperrier5998
2 жыл бұрын
setjmp/longjmp a're typically used to restart a program. Call setjmp() first thing in main() This is how a service restarts without losing its connections, or how configuration reload can be implemented. Some errors like invalid instruction can also be handled by "soft restarting" the program this way. Amazingly, it works great.
@ShotgunLlama
3 жыл бұрын
Will setjmp always save the execution context to whatever is passed to it, discarding anything already in that jmp_buf? In other words, as shown here, this wouldn't work for nested try/catch blocks, would it?
@TomStorey96
2 жыл бұрын
I believe he said you could nest if you used different jmp_bufs.
@marusdod3685
3 жыл бұрын
woah didn't know this
@unchayndspersonalaccount7690
3 жыл бұрын
He starts talking about setjmp and longjmp at 3:02
@edgeeffect
2 жыл бұрын
2:25 "...any other language that's not Ruby, Python Java or pretty much any language that's not C" ... or Rust!! ;) It's one of the things that's always made me think exceptions are "hokey"... While, Until, Case, etc can all be emulated by simple IFs and GOTOs... and once they're in object code that's exactly what they are... but exceptions and exception handling???? ... PEP-20: "If the implementation is hard to explain, it's a bad idea. If the implementation is easy to explain, it MAY be a good idea." The fact that this isn't as "pretty" as a real try-catch block is just revealing the truth that exceptions are a damned ugly way of handling errors. In PHP-land we use exceptions to handle control logic as well as exceptional circumstances and it makes me sick-up in my mouth a little bit whenever I have to do it. Speaking as someone who doesn't really like C that much, I would say it's lack of exceptions is actually one of it's huge PLUS points.
@wChris_
3 жыл бұрын
this doesnt handle x86 exceptions! there is a Microsoft try-except extension you can use tho
@islandcave8738
3 жыл бұрын
Couldn't you have used static, instead of a global variable?
@embeddor2230
3 жыл бұрын
Can't believe how crappy this is, and yet so exciting :D Wonder if this is more effecient than normal exception handling from C++.
@casperes0912
3 жыл бұрын
This feels a tiny bit like a goto. Here it at least maintains the structure of the program but it feels like it could easily fall into the same problems the goto has. Though again in this case it doesn't seem to break the integrity of structured programming
@alex_8704
3 жыл бұрын
This is a very interesting and informative video, especially on pre-processing huckery. But try/catch is appealling when we want to catch the runtime errors, not just some conditioning in our algorithm. :)
@viacheslav1392
2 жыл бұрын
exceptions in other languages are the result of conditioning... Conditioning happens at runtime...
@alex_8704
2 жыл бұрын
@@viacheslav1392 Fair enough
@benjaminshinar9509
3 жыл бұрын
love the video, hate the function.
@JacobSorber
3 жыл бұрын
That's fair. Do you have a preferred alternative?
@alantao3810
3 жыл бұрын
😍😍😍😍
@debasmitroy1694
3 жыл бұрын
Kind of ... try catch 😐
@ahmadhadwan
3 жыл бұрын
Thats pretty much what happens under the hood with high level languages, it just checks for the exception and jump to a specified address
@solsticeprojekt1937
Жыл бұрын
this has nothing to do with exception handling. at all.
@KangJangkrik
3 жыл бұрын
Try this: while(true) { fork() } Your PC will start dancing
@laughingvampire7555
Жыл бұрын
no classes, no exceptions, no stl, and you call that "limitations" dude, those are the FEATURES of C. C++ is a stinky pile of unnecessary complexity. embrace error code handling!! exceptions to be useful require static analysis (maybe integrated in the type system) to notify you of uncaught exceptions, are you implementing that? otherwise Exceptions will be a source of pain and maintainability for any piece of software you make. And they are inferior to the condition/restart system of Common Lisp and Smalltalk.
@khankashani7387
3 жыл бұрын
Professor we need c++, all jobs require C++, c is not worth of learning. I don’t see a single company that is asking to learn C or use it at work. Majority is using C++, C#, Java. If you really want to help us, the students we really need to master C++ with data structures and algorithms for jobs and interviews and problem solving. C is almost dead ☠️. It’s all C++ we need, please make C++ videos!!!!
@vespert0
2 жыл бұрын
You need to pull your head out of the sand or some cavity. C is still widely used in many areas, such as embedded computing, automotive, drivers, any application where speed is paramout, etc. Just because you don't see the need for it doesn't mean there isn't one. Also, don't be naive: the majority of those "C++" jobs are advertised as "C/C++" which 99% of the time means you'll be supporting legacy "C with classes" code.
@happygofishing
Ай бұрын
Phull sapart saar
@yimokkh3984
Жыл бұрын
Нихуя не понял, можно на русском?
@abdullahamrsobh
3 жыл бұрын
before watching the video, let me guess, this would probably use goto
@googavo1d
3 жыл бұрын
maybe some call/ret manipulations since it ends up at the setjmp just before it returns and changes return value to >0 so that cmp eax,0 would result in false
Пікірлер: 137