How to use the volatile keyword in C?

  Рет қаралды 68,148

Jacob Sorber

Jacob Sorber

Күн бұрын

Patreon ➤ / jacobsorber
Courses ➤ jacobsorber.thinkific.com
Website ➤ www.jacobsorber.com
---
What is the volatile keyword in C, and how does it work?
Some of you for a video about "volatile"- a keyword that concerns and mystifies a lot of beginning programming students. I hope this video demystifies it for you, with some simple examples.
Related Videos:
Threads ( • How to create and join... )
Signals ( • Sending and Handling S... )
Optimizations ( • Make existing code run... )
***
Welcome! I post videos that help you learn to program and become a more confident software developer. I cover beginner-to-advanced systems topics ranging from network programming, threads, processes, operating systems, embedded systems and others. My goal is to help you get under-the-hood and better understand how computers work and how you can use them to become stronger students and more capable professional developers.
About me: I'm a computer scientist, electrical engineer, researcher, and teacher. I specialize in embedded systems, mobile computing, sensor networks, and the Internet of Things. I teach systems and networking courses at Clemson University, where I also lead the PERSIST research lab.
More about me and what I do:
www.jacobsorber.com
people.cs.clemson.edu/~jsorber/
persist.cs.clemson.edu/
To Support the Channel:
+ like, subscribe, spread the word
+ contribute via Patreon --- [ / jacobsorber ]
+ rep the channel with nerdy merch --- [teespring.com/stores/jacob-so...]
Source code is also available to Patreon supporters. --- [jsorber-youtube-source.heroku...]
Want me to review your code?
Email the code to js.reviews.code@gmail.com. Code should be simple and in one of the following languages: C, C++, python, java, ruby. You must be the author of the code and have rights to post it. Please include the following statement in your email: "I attest that this is my code, and I hereby give Jacob Sorber the right to use, review, post, comment on, and modify this code on his videos."
You can also find more info about code reviews here.
• I want to review your ...

Пікірлер: 109
@JacobSorber
@JacobSorber 4 жыл бұрын
A few of you have pointed out that volatile does not provide atomicity and shouldn't be used for atomicity. This is absolutely correct. My point in using threads in this example was simply to illustrate that threads can cause the compiler to optimize out your variables. For atomicity, please use locks, synchronized variables (if you're using java), or atomic datatypes if your language/compiler/platform supports them.
@bastawa
@bastawa 4 жыл бұрын
Its very crucial to use volatile when reading micro controllers inputs
@JacobSorber
@JacobSorber 4 жыл бұрын
Yeah, that's really where I end up using volatile the most.
@bastawa
@bastawa 4 жыл бұрын
@@JacobSorber This actually made your video even more valuable, because when reading microcontroller input if you forget to use volatile, you will know there's something wrong with the code regardless of compiler flags / build settings. Great video as always!
@cainabel2553
@cainabel2553 Ай бұрын
For MMIO? Compilers often have compiler specific primitives for that, and they then adapt each other primitives to make them portable.
@cainabel2553
@cainabel2553 Ай бұрын
@@bastawa If you compile at the lower possible optimization level, or in fully debug-able mode, no, you won't feel the missing volatile.
@ABaumstumpf
@ABaumstumpf 3 жыл бұрын
I think a slightly better explanation in this case is how it is described in the c++ standard: Volatile is a marking that says that any access of that variable (read or write) has effects that can not be seen from the code. So when reading from or writing to the variable it has to actually be done as it can change something else. The compiler is allowed to optimize it but just not reorder it in relation to other things with visible effects - visible is anything that changes the observed behaviour like i/o for example. And while it often is used for threads it SHOULD NOT be relied upon as there is no guarantee about timings or even data propagation. Having 2 threads signalling each other via a volatile is NOT guaranteed to work. It basically only works for memory-mapped IO. Prior to C11 there is no standard way to have defined behaviour for multithreaded access to any data. There are Compiler-extensions but they are of course not portable and do not support all hardware either. And with C11 "atomic" is the thing you want to use.
@Gilgamesh557
@Gilgamesh557 2 ай бұрын
The reason why the confusion exists with multithreading is that it has a different meaning in java, where it additionally imposes memory barriers, effectively making reads and writes atomic. However, as you wrote, it is clearly mentioned in the c++ guidelines that atomics should be used for synchronization in c++
@israeldlr4365
@israeldlr4365 3 жыл бұрын
I just found a video of this guy like an hour ago and this is my 6th in a row of very specific concepts that he manages to pull of crystal clear in under 6 minutes. I feel so blessed to find him because there is literally a hundred videos made with laptop microphones and hard to follow audio that just write jibber into the screen and give 20 minute obscure explanations without going nowhere. Seriously Reading the K&R book gave me a lot better understanding but even they start to babble like compilers in some paragraphs, the idea is so abstract the concept just gets lost without a concise example. This guy understands it so clearly and with so simple examples that just opens your mind and makes you go "was that all?". Einstein was indeed right when he said that if you cannot explain something plain simple you may not understand it very well yourself, granted this has not an universal application but oh my is just so evident in cases like this. Instant subscribe, I love this guy, this is the enlightenment I was looking to find among the sea of explanations.
@trichomaxxx
@trichomaxxx 3 жыл бұрын
I come here often and always learn something new, his videos are of immense quality. To the point, easy to understand and without any hint of elitism.
@tceffect2353
@tceffect2353 4 жыл бұрын
The reason why the program worked when sleep was called was because the compiler has to reload all globals from memory to registers after a function is called(unless the compiler can prove that the function can't access or modify the global)(library functions like sleep can't be proved to not modify a global unless they are declared inline because they are in a different translation unit). The reasoning behind this rule is that when the compiler compiles the caller function it doesn't know if the callee modifies the global variable, so it needs to write the global to memory if it was modified before the function is called, and load it back from memory (into a register) once the function returns(this is one of many reasons that globals make code optimization worse).
@JacobSorber
@JacobSorber 4 жыл бұрын
Thanks.
@mogenshansen7210
@mogenshansen7210 2 жыл бұрын
Og does not work - the program has data race, which is undefined behaviour. The worst case of undefined behaviour is when it is not obvious that the program is broken
@unperrier5998
@unperrier5998 2 жыл бұрын
indeed. Looking at the disassembly, when an external function is called, the compiler includes fetching and comparing the "done" variable. If the function is not external (for example we can use a recursive function like factorial, it will not be optimized) then we see the function being called, but the fetch and compare isn't. I've tried building a shared library that has a very simple function returning a constant, and when calling that function instead of sleep() the compiler removes optimization. Even when "done" is made static, compilers (gcc and clang) don't optimize away the fetch and compare. So it's clearly because we make an external function call.
@bullsvip
@bullsvip 3 жыл бұрын
This exact question came up on my Qualcomm internship interview and I got the offer! Thanks for making this video. I would not have been able to answer it otherwise. I'm glad I found this vid by chance before the interview
@JacobSorber
@JacobSorber 3 жыл бұрын
Congrats! Glad it was helpful!
@tceffect2353
@tceffect2353 2 жыл бұрын
I work at Qualcomm on the GPU compiler team. What team in the company to you work on?
@paedestrian
@paedestrian 3 жыл бұрын
Very well explained along with an easy to understand example. Thank you very much
@barsvelioglu2276
@barsvelioglu2276 3 жыл бұрын
Clear explanation. Tells the compiler not making any assumptions about the property with the word volatile
@VTdarkangel
@VTdarkangel 4 жыл бұрын
I always wondered what that was for. I was told to use volatile for data input addresses for my intro embedded class in school, but was never really told why. I figured it had something to do with what you described, but wasn't sure.
@tanmayagarwal8513
@tanmayagarwal8513 2 жыл бұрын
Ur video made much more sense than any other video! Thanks a lot! U earned one more subscriber!
@EmanuelZimmermann
@EmanuelZimmermann 3 жыл бұрын
I had to pause the video to leave you a message. I just cannot stress how good the content is. Thank you. Been watching your videos like Netflix while I have supper.
@JacobSorber
@JacobSorber 3 жыл бұрын
Thanks, Emanuel.
@taragnor
@taragnor 3 жыл бұрын
Thanks. I was always confused when you'd use volatile before this video. That was a great explanation.
@shivakaramadi9444
@shivakaramadi9444 4 жыл бұрын
Great work! Thank you so much for explaining it with example so easy to understand.
@JacobSorber
@JacobSorber 4 жыл бұрын
You're welcome. Glad I could help.
@ayanarif1
@ayanarif1 2 жыл бұрын
That was really amazing man! Thanks you for this video. Please keep posting more videos
@laminekaba3064
@laminekaba3064 4 жыл бұрын
Thanks Jacob for your quick response about my request. I used volatile to catch signals on my Shell project. After reading many books and tutorials about volatile, this one is straight forward and well explained. Also noticed your videos are getting better. Good job.
@JacobSorber
@JacobSorber 4 жыл бұрын
You're welcome. It was an easy one to throw together quickly (examples were short) and seemed to fit with the embedded videos I've been making (and am planning to make).
@chezhiyanspartan5080
@chezhiyanspartan5080 Жыл бұрын
clear as crystal!
@spaceinvader8892
@spaceinvader8892 3 жыл бұрын
Cool explanation & cool example.
@Universaeducation
@Universaeducation 2 жыл бұрын
Thank you so much. Very well explained.
@Adem-ur2di
@Adem-ur2di 4 жыл бұрын
thank you very much Mr.Jacob , Your videos are really very useful and Point shot ! I am working on embedded systems and I recommend you to the people and I hope that You can post more videos! About embedded systems, Rtos , Linux .. file systems Compilers ....etc ☺️👍 Thanks again
@Steezylegs_juri
@Steezylegs_juri 8 ай бұрын
very good explanation thanks
@misanthropicmusings4596
@misanthropicmusings4596 3 жыл бұрын
almost a year in the future -- this is a great explanation of volatile. I saw it in some code and the Microsoft documentation was a little confusing. Thanks!
@rafalmichalski4893
@rafalmichalski4893 4 жыл бұрын
Great material. Thanks Jacob !
@JacobSorber
@JacobSorber 4 жыл бұрын
My pleasure!
@ajidaniel8818
@ajidaniel8818 4 жыл бұрын
Dude ... You are the best
@dl4006
@dl4006 4 жыл бұрын
Love your channel, you're doing great work. Keep it up!
@JacobSorber
@JacobSorber 4 жыл бұрын
Thanks.
@momoanddudu
@momoanddudu 4 ай бұрын
volatile is intended for memory mapped registers - a mechanism for CPUs to communicate with I/O devices. This means two important things. First, every access to a volatile has to go all the way to the memory (read: it may not be cached), making accesses to volatile slower than non-volatile variables. Second, access to volatiles may not be reordered within a given thread, as a device might react differently depending on the order in which registers are accessed. [To simplify things, say the protocol is for the CPU to write to a disk drive's R1 a sector number, to R2 a RAM address, to R3 whether to write from memory to disk or read from disk to memory, and the write to R3 triggers the operation. The programmer would write to R1 & R2 first, and R3 last, and the compiler & CPU must keep the order, or the disk drive might trigger the operation with the wrong values in R1 & R2. Neither has to care about any other variables, unless used to compute the values stored to the volatile variables.] C++ atomics *are* meant for synchronization, and therefore behave differently. If a program runs on a CPU which has cache coherency protocols, every access to an atomic has to go to the cache, but not necessarily to the RAM. More importantly, atomics are memory barriers / fences, meaning not only access to atomic variables ordered, access to all other variables is ordered as well. If a thread writes to an atomic variable with memory order release fence, the compiler and CPU have to guarantee every memory access prior to it in the source code must occur before it when the program executes. Reading from an atomic variable with memory order acquire means every memory access after it in the source code must occur after it when the program execute, and more specifically if a variable was read into a register prior to it, it must be reread again after it.
@davidgillies620
@davidgillies620 6 ай бұрын
In addition to not providing atomicity, the compiler is free to reorder non-volatile memory accesses around the volatile access. This can introduce some really subtle bugs. In C++ the atomics work as expected (as a memory barrier), and you also have std::memory_order/std::atomic_thread_fence to really nail down your memory access semantics.
@finmat95
@finmat95 Жыл бұрын
"Volatile variables everywhere? this is the worst code i've never seen" "Yea but it runs!"
@TheRojo387
@TheRojo387 5 ай бұрын
Reserve "volatile" for variables dependent on user input or IPC.
@tusharghadge5549
@tusharghadge5549 3 жыл бұрын
Thank you
@KangJangkrik
@KangJangkrik 3 жыл бұрын
TL;DW use volatile if that global variable will be accessed by other thread, signal handler, or interrupt (in microcontroller like Arduino). Thanks again Jacob Sober, you save my day EDIT: This video is not too long, it just perfect 👌 I want to make it shorter to help other beginners
@sumitbhosale3401
@sumitbhosale3401 4 жыл бұрын
Perfect Video. Nice Explanation. But Waiting For HashTable. Thank You
@JacobSorber
@JacobSorber 4 жыл бұрын
Thanks. It's coming.
@anonanon3066
@anonanon3066 3 жыл бұрын
Awesome! Thanks!
@JacobSorber
@JacobSorber 3 жыл бұрын
My pleasure.
@leanobajio
@leanobajio 4 жыл бұрын
Wow! That was very accessible information about C. Great work!
@JacobSorber
@JacobSorber 4 жыл бұрын
Thanks. Glad you liked it.
@kathiravankathir3089
@kathiravankathir3089 4 жыл бұрын
Thanks.
@JacobSorber
@JacobSorber 4 жыл бұрын
You're welcome.
@omaral-wadi8746
@omaral-wadi8746 4 жыл бұрын
شكرا
@JacobSorber
@JacobSorber 4 жыл бұрын
You're welcome.
@shayitzhakey593
@shayitzhakey593 3 жыл бұрын
Amazing
@mohamednabil1709
@mohamednabil1709 4 жыл бұрын
@jacob. This is my first KZbin comment. But I just wanted to say you awesome
@JacobSorber
@JacobSorber 4 жыл бұрын
Thank you. I needed that, today.
@almosteasy9590
@almosteasy9590 4 жыл бұрын
It will nice if you make video on Bit Masking. :)
@24680kong
@24680kong Жыл бұрын
As a novice programmer, it makes me unreasonably angry that I have to add a special keyword to ensure the compiler actually uses the code I wrote. I appreciate that compilers can help seed up code, but failing to check a function call seems like a pretty big oversight.
@J_Tanzanite
@J_Tanzanite 4 жыл бұрын
Your upload schedule is volatile, that explains why notifications don't work! Jk, love your stuff, keep it up man! cx
@JacobSorber
@JacobSorber 4 жыл бұрын
You're not wrong. Thanks.
@islandcave8738
@islandcave8738 3 жыл бұрын
In the allegro game library, the mouse position is defined as volatile.
@TheRojo387
@TheRojo387 5 ай бұрын
In short, volatile is useful for handling modification by input, be it by IPC or by the user.
@AlejandroAnzolaAvila
@AlejandroAnzolaAvila 2 жыл бұрын
I just noticed that a lot of problems that I had while I was doing for a research project that involved pthreads and shared resources could have worked if I had used this keyword, too bad that I found out about it 3 years after
@noxagonal
@noxagonal 2 жыл бұрын
Just in case you didn't know, you really shouldn't use volatile between threads at all. To synchronize execution use mutexes and to share data between threads on the fly, use atomics. Volatile is only there to make sure memory for the variable doesn't get optimized away and that the reads and writes are fetched from memory, this does not guarantee CPU cache coherency between threads, which may lead one thread to see an incorrect value for a long time until the changes propagate up the CPU cache levels. EDIT: Also I forgot... The compiler and the CPU are allowed to reorganize code and instructions to make execution more efficient or faster. This also means that if you use a volatile variable to flag completion, it may be toggled before the threaded function has finished writing all the data into memory, which may lead to another thread reading incorrect results. I think it's obvious why this is a bad idea. The only real use for volatile nowadays is with microcontrollers with only one thread, where a value may be changed by an outside condition, eg, physical pin taken high or low.
@Handskemager
@Handskemager 2 жыл бұрын
So don’t use volatile except when necessary to stop compiler optimizing breaking code. Is it good style to include a comment about why that particular variable is volatile or?
@JacobSorber
@JacobSorber 2 жыл бұрын
It sounds like a good practice to me.
@murtazahussain6301
@murtazahussain6301 3 жыл бұрын
In embedded systems, I always use volatile with variables which are changed in ISRs.
@wiktorwektor123
@wiktorwektor123 2 жыл бұрын
This is logical, because you don't know when interrupt can happen and as a result variable can change outside of main loop.
@Gnisha
@Gnisha 4 жыл бұрын
Please no not use volatile for multi-threaded programming, especially not for locks. Use the provided atomic structures by the language environment. The compiler and the CPU is allowed to reorder instructions and operations, leading to the very real possibility that the unlock is performed before the last access to the protected data structure happened. This could be fixed by compiler or memory barriers but this is not portable in the least. Using volatile for multi-threading & memory barriers should only ever be relevant in academic settings or when writing OS or LE functions. Volatile should be primarily used to access hardware register mapped into memory where the the hardware is owned and changes by the device.
@JacobSorber
@JacobSorber 4 жыл бұрын
Absolutely agree. I used threads to give an example of when the optimizer gets it wrong. Volatile is not a synchronization primitive.
@ashoksahu1926
@ashoksahu1926 4 жыл бұрын
@@JacobSorber Could you please touch upon what the other user is trying to say? Also if you could touch upon cases when we need locks and when we don't (if any). should we use volatile key word for shared variables which are protected by locks [but not for locks]
@JacobSorber
@JacobSorber 4 жыл бұрын
@@ashoksahu1926 I use volatile most often when I'm writing interrupt service routines for embedded systems. In those cases, my concern is not synchronization or avoiding race conditions, but just making sure that the compiler doesn't optimize away my variables thinking that they are never updated.
@bmuralikrishna8054
@bmuralikrishna8054 4 жыл бұрын
The best example of using volatile is when we are using shared memory.
@ronnysherer
@ronnysherer 4 жыл бұрын
I wonder if the compiler optimizes out the variable or caches it to a register. The behavior would be the same.
@JacobSorber
@JacobSorber 4 жыл бұрын
Good point.
@ramcool82
@ramcool82 2 жыл бұрын
You should have shown assembly output of code for better understanding
@edgarbonet1
@edgarbonet1 2 жыл бұрын
Re “I could [...] just replace this code with ‘while (true) {}’”: That sounds like an unsafe optimization to me: there is stuff from the C runtime that runs before main, what if that stuff touched `done'? If I were the compiler, I would play safe and replace that code with if (!done) while (true) {}
@EduardoMedinaEdlinks
@EduardoMedinaEdlinks 3 жыл бұрын
Why didn't I find this channel before 😭😭😭?
@kvnagendra5354
@kvnagendra5354 4 жыл бұрын
Hey, plz tell me the name of the intro music
@kuler6892
@kuler6892 3 жыл бұрын
it's the song "urban lullaby" and it's from the youtube audio library. It's available for use by anyone on youtube without having to worry about copyright.
@chrissaltmarsh6777
@chrissaltmarsh6777 2 жыл бұрын
If you are close to the metal (where the real fun is. IMHO) you need volatile. Because that byte you're pointing to really is going to change, so tell the compiler.
@hetsmiecht1029
@hetsmiecht1029 3 жыл бұрын
I have a question: If the two threads run on a different core, can't it happen that the variable stays in (not shared) cache and that the program is never notified of the change to the variable? Does volatile somehow prevent that or should you use atomic instructions that notify all cores of a change to the variable? Another question: what about pointers to pointers (e.g. int** varName)? Can you have a non-volatile pointer pointing to a volatile pointer pointing to a non volatile int? How does that look? int* volatile * varName;
@mogenshansen7210
@mogenshansen7210 2 жыл бұрын
Yes - that is why the video is downright wrong
@dorquemadagaming3938
@dorquemadagaming3938 4 жыл бұрын
Why the optimization is not happening if you put a sleep() in between? I think not because of some super heuristics, but because you are calling a function there. And that function potentially has access to that global variable and may modify it. But in an empty loop - you never leave that loop or modify the variable yourself, so technically nobody else should... except for another thread or a signal handler.
@JaSamZaljubljen
@JaSamZaljubljen 4 жыл бұрын
1:32 did you mean "except" instead of "accept"
@JacobSorber
@JacobSorber 4 жыл бұрын
Yep. Good catch.
@diwakar8815
@diwakar8815 4 жыл бұрын
hey jacob i am preparing for an entrance exam for a institute. The syllabus is 8086 microprocessor. can you recommend me any textbook that is good for learning 8086???
@JacobSorber
@JacobSorber 4 жыл бұрын
What specifically are you looking for? An assembly-level guide? Descriptions of the hardware features and instruction set architecture?
@diwakar8815
@diwakar8815 4 жыл бұрын
Complete guide
@steinmil
@steinmil 4 жыл бұрын
Good info. Bite sized , to the point. So first try and compile with all debug and no optimization enabled. As soon as you build the thing and use optimization then you get hangs and/or crashes. Any way to avoid this ? Can you at least get a heads up of what was optimized in the form of a report, from the compiler ? Or do you need to look at the disassembled code ? Or maybe write tests and pray they cover this situation. You would need to know the compiler pretty well to say that something is volatile and should be treated without optimization.
@JacobSorber
@JacobSorber 4 жыл бұрын
I don't know of a way to get the compiler to report what it optimized away. It would be a fairly useful tool to have, though. I usually just think about how variables are accessed. If a variable is changed in an interrupt service routine, for example, then it should probably be volatile. I'll let you know if I find something better.
@paulzupan3732
@paulzupan3732 Жыл бұрын
I feel like the first example is less of a testament to the usefulness of the volatile keyword and more of a warning to just never use global variables
@tosemusername
@tosemusername 3 жыл бұрын
The only way to make this video perfect is to show the assembly generated.
@user-kh6rp6yx1j
@user-kh6rp6yx1j 4 күн бұрын
Hey man.
@manoj_kumar_sarkar
@manoj_kumar_sarkar 4 жыл бұрын
comment
@glowiever
@glowiever 3 жыл бұрын
java programmer is less scared though
@tomershechner
@tomershechner 4 жыл бұрын
How's it in Africa?
@JacobSorber
@JacobSorber 4 жыл бұрын
I'm enjoying it. Great people. Cool things to see. And, it's just fun to mix things up.
@tomershechner
@tomershechner 4 жыл бұрын
@@JacobSorber Wow. Sounds so cool. I wish I could've visit Africa someday..
@mogenshansen7210
@mogenshansen7210 2 жыл бұрын
The use of volatile in relation to thread syncronisation is just pure WRONG! It is a common misconception, which does not get more correct by being repeated. The examble exhibits undefined behaviour regardless of whether you use volatile or not, and that is the reason for the inconsistent behaviour that you demonstrate. Please either compile with ThreadSanitizer or read the language spec. This video should be removed! Volatile prevent the compiler from optimizing reads, so it is for accessing hardware that may change unrelated to the software - like a real time clock hardware circuit
@BowBeforeTheAlgorithm
@BowBeforeTheAlgorithm 2 жыл бұрын
This is exactly right. It's even more confusing because Microsoft visual C++ compiler actually has a flag that transforms usage of the volatile keyword into atomic machine code.... dependent on your project settings, that volatile to atomic switcheroo is on by default. It's helpful but allows and reinforces incorrect usage. I've only seen one correct use of volatile in my career and it was when reading directly from hardware memory (an sd card device).
How to measure memory usage inside my program? (getrusage)
13:08
Jacob Sorber
Рет қаралды 30 М.
What is a semaphore? How do they work? (Example in C)
13:27
Jacob Sorber
Рет қаралды 288 М.
Василиса наняла личного массажиста 😂 #shorts
00:22
Денис Кукояка
Рет қаралды 10 МЛН
Alat Seru Penolong untuk Mimpi Indah Bayi!
00:31
Let's GLOW! Indonesian
Рет қаралды 14 МЛН
Was ist im Eis versteckt? 🧊 Coole Winter-Gadgets von Amazon
00:37
SMOL German
Рет қаралды 29 МЛН
The Embedded Way - The volatile keyword in C
5:47
Siemens Embedded
Рет қаралды 44 М.
When do I use a union in C or C++, instead of a struct?
11:18
Jacob Sorber
Рет қаралды 67 М.
What role has the VOLATILE keyword in Java?
9:08
Visual Computer Science
Рет қаралды 18 М.
The Most Useless Keyword in C?
10:26
Jacob Sorber
Рет қаралды 68 М.
The ONLY C keyword with no C++ equivalent
13:17
mCoding
Рет қаралды 266 М.
The Absolute Best Intro to Monads For Software Engineers
15:12
Studying With Alex
Рет қаралды 602 М.
Bit Fields in C. What are they, and how do I use them?
13:26
Jacob Sorber
Рет қаралды 79 М.
the cleanest feature in C that you've probably never heard of
8:13
Low Level Learning
Рет қаралды 128 М.
Make your Data Type more Abstract with Opaque Types in C
13:41
Jacob Sorber
Рет қаралды 48 М.
Василиса наняла личного массажиста 😂 #shorts
00:22
Денис Кукояка
Рет қаралды 10 МЛН