I'm not sure this'll ever be of use to me, especially with the amount of pointer casting that I'd rather avoid, but that was nonetheless really interesting to know and see working, thanks!
Thank you Jacob for the mention. For the short but explanatory video format that is yours, I had in mind a simple wrapper around printf() that would only handle the "%U" string (with only one argumentto printf), not in confunction with other formats and arguments. But your approach is better yet concise, although GNU specific.
Interesting that your callback is always given a FILE*, while the printf family includes functions for writing to preallocated strings, dynamically-allocated strings, and even direct file descriptors. Presumably in all these cases, the glibc wrapper creates temporary FILE* objects as the common denominator for invoking your callback, and likely all the rest of its internal machinery as well.
This is certainly neat, and I wish they would add such functionality to the standard, albeit in a slightly different way. This is at least part of why I've been developing my own language. Sometimes it feels a bit like an addiction. It all started with implementing the functions in string.h and by the time I got done rewriting libc, I just couldn't stop. By the time I'm done, it may actually be enticing enough for others to use it, assuming I ever release it. You've actually inspired me to add a few features into my language. This video only reinforced my belief that I was right to extend my own printf() and have a way to add format specifiers. Though, it won't be compatible with C's printf(), at least not fully, even by default.
Funny that one can do that in UNIX derivative Linux. The UNIX philosophy used to be "build complexity from assembling small, simple units", not "let's muddy things because we can." 'cat' used to be simply "concatenated files to the standard output"... Then some bright lad thought it should also add line numbers... and skip numbering blank lines... and squeeze out multiple blank lines... and makes tabs visible... and make EOL visible, too... In fact, make everything visible! Poor cat... Thanks for an Interesting video,. My preference would be to KISS... Push the UUID gen/parse into a function that returns a string (formatted to suit) and simply use '%s'. Just because one CAN do something, does that mean one SHOULD??
Certainly is interesting, didn't know you could do that, I still prefer to go with my custom version of "sprintf", basically I wrote the whole thing to just deal with UTF32 characters then had my other custom string functions just use it under the hood with some temporary buffers, added all the standard specifiers then added a couple of my own like %?b for bit sequences (where ? is d, i or u like the standard integer specifiers), and %?p to take intptr_t/uintptr_t. Took me a while to get it right (mostly because I made some errors in my string growth handlers which I didn't notice until way after I started). Seeing this I realise I should refactor that function and do something similar to the above, saving to watch later for now as it's not a priority, however instead of declaring the format specifier I think I'll instead go with a list of function pointers to call every time the % character is encountered, I'll also declare the built in specifiers via public functions and a macro for the lot to be put in the expected array so that the order of which specifiers to check for plus what to actually look for can be specified manually, something like: int xprintf( char *args, ... ) { int ret; va_list list; va_start( list, args ); ret = xprintv( args, list ); va_end( list ); return ret; } int stdout_foo(uuid_t id) { xprint_wr_func funcs[] = { XPRINT_WR_WITH, wr_uuid }; xprint_wr_with with = { stdout, (vprintx_wr_cb)fwrite, funcs, sizeof(funcs) / sizeof(funcs[0]) }; return xprintf( "%WITH%UUID", &with, &uuid ); }
In C++20 a new format function has finally been added to the standard library that allows Python style formatting of strings. It's pretty cool because you can add format specifier and it's supported by the standard! However i think only MSVC has a working implementation at the moment
Thanks for the video... And a Request, Please make a video on explaining the In and out of Stdio.h header files, to explain how printf functions works behind the functions, how printf function uses system calls to print the data on screen.. if possible how system calls implement printing of data to console or screen, please...
Alternatively, one could look to the example of "strftime()" and write a more intuitive, flexible and portable function that is compiler and library independent.
Hi, will you make a video on how to organize and manage between header files and source files. I actually get stuck in these organizing problem when I try to expand my project.
This feels a bit dodgy. The fact it'll spam errors at you unless you disable the format specifier warnings would certainly keep me away from it and I'd rather find alternatives. That and dodgy documentation doesn't help either.
printf is inherently typesafe. Compiler warnings on the format string are essentially a kludge on top of a kludge; they help with the simpler cases, but just get in the way of the more advanced cases (like this one).
va_list is nice but it's the tip of the iceberg as it only deals with arguments. You need to find out the size of each argument and to be compatible with printf() you'd need to implement all the cases and modifiers that printf() supports, including references to write values back into memory. The switch-case that results is big and would take a 2h video.
how do l create a code that carry's out the some function as printf but without using printf and co. (fprintf, sprintf, snprintf, asprintf, dprintf, vprintf, vfprintf, vsprintf, vsnprintf, vasprintf, vdprintf)
I mean, there's always a chance. That would probably require me to actually use Windows, right? Do you know where I can find the Windows kernel source code?
From the header on Macos: /* * We don't support the GLIBC register_printf_function() or FreeBSD * register_printf_render_std(), because they affect printf globally * and are unsafe. */ So, indeed: not very portable.
Oh EM G! You used FILE *s and printf_info *i ... So culturally inappropriate. Longstanding unwritten norms hold that "s" will probably be a string, and "i" will probably be an integer iterator or index (or, rarely, a complex number). Additionally, in instruction material FILE *fh; is generally used. Please excuse my flame, it stems from using C since its predecessor BCPL.
bro, why do people still use this old language, don't you think it is time to switch to a more modern solutions (i.e rust)?. if you think about it. using c will always lead to memory corruption issues no matter how good you are
I'm not sure this'll ever be of use to me, especially with the amount of pointer casting that I'd rather avoid, but that was nonetheless really interesting to know and see working, thanks!
Thank you Jacob for the mention.
For the short but explanatory video format that is yours, I had in mind a simple wrapper around printf() that would only handle the "%U" string (with only one argumentto printf), not in confunction with other formats and arguments. But your approach is better yet concise, although GNU specific.
Learnt a lot from this video! Wanna see more deep dives like this one
Interesting that your callback is always given a FILE*, while the printf family includes functions for writing to preallocated strings, dynamically-allocated strings, and even direct file descriptors.
Presumably in all these cases, the glibc wrapper creates temporary FILE* objects as the common denominator for invoking your callback, and likely all the rest of its internal machinery as well.
This is certainly neat, and I wish they would add such functionality to the standard, albeit in a slightly different way. This is at least part of why I've been developing my own language. Sometimes it feels a bit like an addiction. It all started with implementing the functions in string.h and by the time I got done rewriting libc, I just couldn't stop. By the time I'm done, it may actually be enticing enough for others to use it, assuming I ever release it. You've actually inspired me to add a few features into my language. This video only reinforced my belief that I was right to extend my own printf() and have a way to add format specifiers. Though, it won't be compatible with C's printf(), at least not fully, even by default.
epic
Logging in c would be a good one. Like different handlers, streams etc.
Funny that one can do that in UNIX derivative Linux.
The UNIX philosophy used to be "build complexity from assembling small, simple units", not "let's muddy things because we can." 'cat' used to be simply "concatenated files to the standard output"... Then some bright lad thought it should also add line numbers... and skip numbering blank lines... and squeeze out multiple blank lines... and makes tabs visible... and make EOL visible, too... In fact, make everything visible!
Poor cat...
Thanks for an Interesting video,.
My preference would be to KISS...
Push the UUID gen/parse into a function that returns a string (formatted to suit) and simply use '%s'.
Just because one CAN do something, does that mean one SHOULD??
Certainly is interesting, didn't know you could do that, I still prefer to go with my custom version of "sprintf", basically I wrote the whole thing to just deal with UTF32 characters then had my other custom string functions just use it under the hood with some temporary buffers, added all the standard specifiers then added a couple of my own like %?b for bit sequences (where ? is d, i or u like the standard integer specifiers), and %?p to take intptr_t/uintptr_t. Took me a while to get it right (mostly because I made some errors in my string growth handlers which I didn't notice until way after I started).
Seeing this I realise I should refactor that function and do something similar to the above, saving to watch later for now as it's not a priority, however instead of declaring the format specifier I think I'll instead go with a list of function pointers to call every time the % character is encountered, I'll also declare the built in specifiers via public functions and a macro for the lot to be put in the expected array so that the order of which specifiers to check for plus what to actually look for can be specified manually, something like:
int xprintf( char *args, ... )
{
int ret;
va_list list;
va_start( list, args );
ret = xprintv( args, list );
va_end( list );
return ret;
}
int stdout_foo(uuid_t id)
{
xprint_wr_func funcs[] = { XPRINT_WR_WITH, wr_uuid };
xprint_wr_with with = { stdout, (vprintx_wr_cb)fwrite, funcs, sizeof(funcs) / sizeof(funcs[0]) };
return xprintf( "%WITH%UUID", &with, &uuid );
}
In C++20 a new format function has finally been added to the standard library that allows Python style formatting of strings. It's pretty cool because you can add format specifier and it's supported by the standard! However i think only MSVC has a working implementation at the moment
But also it's C++ 20 only (I mean technically 23 too, but you know what I mean). Also it's worse performance wise, that printing directly
in C++ 30 we'll get python 3.6+ f-strings :)
@@tk36_real It's WAY faster than printf.
Thanks for the video... And a Request, Please make a video on explaining the In and out of Stdio.h header files, to explain how printf functions works behind the functions, how printf function uses system calls to print the data on screen.. if possible how system calls implement printing of data to console or screen, please...
This might be useful when we're trying to print a struct for some reason
amazing to see this!
Just wanted to say you can use the old approach with dlsym and looping through string (and checking for %u)
interesting !
another option would be function hooking
Your content is amazing
Thanks. Glad you like it.
Alternatively, one could look to the example of "strftime()" and write a more intuitive, flexible and portable function that is compiler and library independent.
Hi, will you make a video on how to organize and manage between header files and source files. I actually get stuck in these organizing problem when I try to expand my project.
Cool! I really want to have a use case for it! 😀
This feels a bit dodgy. The fact it'll spam errors at you unless you disable the format specifier warnings would certainly keep me away from it and I'd rather find alternatives. That and dodgy documentation doesn't help either.
Yep, it was definitely one of those, let's-see-if-we-can moments. I don't think I'll be seeing much use for this in my day-to-day programming.
printf is inherently typesafe. Compiler warnings on the format string are essentially a kludge on top of a kludge; they help with the simpler cases, but just get in the way of the more advanced cases (like this one).
Let's make printf even more non-standard!
printf has a cringe implementation, but if you really wanted to, you could make your own faster print function that wasn't explicitly named printf.
An alternative would be to create a custom printf wrapper using va_list that has additional logic to take care of the new format characters.
va_list is nice but it's the tip of the iceberg as it only deals with arguments. You need to find out the size of each argument and to be compatible with printf() you'd need to implement all the cases and modifiers that printf() supports, including references to write values back into memory. The switch-case that results is big and would take a 2h video.
@@unperrier5998 that's a good point I hadn't considered!
It's probably easier to modify musl libc than glibc.
how do l create a code that carry's out the some function as printf but without using printf and co. (fprintf, sprintf, snprintf, asprintf, dprintf, vprintf, vfprintf, vsprintf, vsnprintf, vasprintf, vdprintf)
Hey Jacob. Could we see any videos on the Windows Kernel sometime and how we can interact with it using C?
I mean, there's always a chance. That would probably require me to actually use Windows, right?
Do you know where I can find the Windows kernel source code?
From the header on Macos:
/*
* We don't support the GLIBC register_printf_function() or FreeBSD
* register_printf_render_std(), because they affect printf globally
* and are unsafe.
*/
So, indeed: not very portable.
How to do finer control like %*.s
Such a fascinating idea. Definitely learnt something new and I feel like I’m going to abuse the heck out of this idea mwuahahaha!
12:47 Extra parentheses are unnecessary.
still waiting for you to show up on odysee...
Anyone with youtube-dl can just reupload to odysee.
How the ":" in this "uint x:1;" is called?
That is a bit field. It specifies that that member of the struct only needs on bit of storage.
Why would someone chose to use C if it's not for a college assignment, it's insane
Oh EM G! You used FILE *s and printf_info *i ... So culturally inappropriate. Longstanding unwritten norms hold that "s" will probably be a string, and "i" will probably be an integer iterator or index (or, rarely, a complex number). Additionally, in instruction material FILE *fh; is generally used. Please excuse my flame, it stems from using C since its predecessor BCPL.
Fortran programmer?
@@lawrencedoliveiro9104 40+ year C/Unix programmer. Although my Dad did teach me Fortran as a kid.
I don't think I'd ever even consider using that 🎃
I'm not sure I will either, but it was a fun adventure.
bro, why do people still use this old language, don't you think it is time to switch to a more modern solutions (i.e rust)?. if you think about it. using c will always lead to memory corruption issues no matter how good you are
this video about nothing