What about Pointer Arithmetic with Void Pointers?
Вставка
- Опубліковано 25 лип 2022
- Patreon ➤ / jacobsorber
Courses ➤ jacobsorber.thinkific.com
Website ➤ www.jacobsorber.com
---
What about Pointer Arithmetic with Void Pointers? // After my recent video about void pointers, some of you commented about pointer arithmetic. So, this is a follow-on video to address this issue. This video talks about why pointer arithmetic with void pointers should be avoided.
Related Videos:
Void Pointers: • The What, How, and Why...
Pointers and Arrays: • Arrays, Pointers, and ...
***
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 ]
Source code is also available to Patreon supporters. --- [jsorber-youtube-source.heroku...]
I'm not sure why every CS/ECE student doesn't follow you. I honestly can't imagine a better source of information than this channel.
Well. I found his variadic macro stuff a bit lack luster. He didnt really explain why there needs to be a named function parameter before the ellipsis. I found some other really good channel that explained. However, it was more dry.
So dont let this be your one and only stop!
(and he is really good. and VERY engaging, which I really enjoy)
What does ECE stand for?
@@Yazan_Majdalawi electrical and computer engineering
He's focusing on the basics ...
There's other ground to cover outside basics.
So other channels...
To meet other needs.
Thanks for shouting out to us here in the Southern Hemisphere!
Your lessons has transformed my code, especially when it comes to optimization. Thanks a lot
Superb i've learn for the first time what casting really means and even more about pointers. Thanks. ❤
Doesn't look like anyone has taken me up on recommending you to learn C with, but I'm going to keep pushing people your way anyhow. Your channel is easily one of the top 5 for programming content, and certainly the number one channel for C.
Thanks. I appreciate it.
@@JacobSorber Hi sir I came across this question why can't we use "if or for or while outside I mean not in any function like globally
I have tried to execute the below code but compiler don't allow to execute and I am getting an error which I have mentioned below
// Online C compiler to run C program online
#include
if(1)
{
}
int main() {
// Write C code here
printf("Hello world");
return 0;
} This is the code
error: expected identifier or '(' before 'if'
3 | if(1)
| ^~ can you pls help me with this question .
@@ramakrishna4092 what did u write if(1) just remove that function
I always increment void pointers directly when I want to add bytes (and I do that a lot in my programs) , I didn't know this was not standard, thanks for the info
I was doing that too, I find it dumb that there is no standard behaviour. Let +1 add one byte, simple and logical, at least to me
@@francescomazzucco6264 The most logical thing is to have the exact same behaviour as with all the other pointer types, i. e. add sizeof(void) when doing "+1".
Then the question arises what the most logical value for sizeof(void) is...
@@Uerdue I think sizeof(void) should be u64 since addresses are that long
@@darioabbece3948 Well, `void` is not neccessarily meant to store addresses. `void*` is. And `sizeof(void*)` indeed equals the number of bytes of an address, so that's 8 or 4, depending on whether you're on a 64-bit or 32-bit machine.
@@darioabbece3948 I'm not sure but isn't sizeof(void) a compile error? Edit: I just checked and my C online compiler spit out 1. So as far as logic goes
void* p;
p += 1
Is equivalent to
p += sizeof(void) ;
Great! Thank you very much!
Fascinating. A long time ago I drove hardware using pointers, that's what you did. You add 2 to a pointer, it is pointing 2 bytes up the line. You get your C code pointer numbers wrong, the code does something wrong. - it'll read the wrong value or write something horrid to your CAMAC. It was rather charming how the original C allowed you to really, really screw up.
This is why I love C and low level. You shouldn't do it, but you are free to try. Full control.
Yeah, I agree. I think this is one of C's greatest strengths, as an education tool, whether or not we choose to use it for every project.
Correction: You stated "The compiler didn't have to do something reasonable, because the C standard doesn't actually support this behavior, it doesn't make any guarantees".
That's in fact not true. The C standard prohibits void pointer arithmetic, so this is not an undefined behavior, it's very clearly defined.
However, having a compiler adding this feature as a "compiler extension" is something completely different than a UB (same goes for something like nested functions with GCC).
Again GCC and other compilers have many extensions (that doesn't make your program undefined as you mentioned in your final words). But if you choose to be strictly compliant with the C standard, you may use some compiler flag like "-Werror=pedantic" and you're good to go.
One thing I might add is that everyone should turn up their warning levels when they compile (I have level4 set when using msvc from the command line). When you do that, it doesn't even let you do pointer arithmetic on void pointers
I was inspired by your void pointer video to build a pointer type in java that works on native memory. While writing the classes I stumbled over this exact problem, "what should p.add(int i) do on a void type." I thought it must be 1 byte but how does languages with pointers do it? And now I have my answers, they don't know it either XD. Thanks for the video.
You're welcome. Glad I could help.
learned this the hard way, way back when 😂
my assumption was that void pointers would always increment by the size of the compiler's integer, but nope. Been using char* since then
That font looks so nice how to set it up ?? plus what colour theme, file icon theme and product theme you use ?? I am learning a lot from you as a Embedded student your videos help a lot to understand C/OS concepts thank you.
I think the font is Menlo, but I'm not sure
will get it. Just don't get burnt out. Whenever you need a break, take one.
Can you explain why in some directx and and opengl functions they ask for void pointers args, when the type of data the pointer is pointing to is always the same i guess? Is it because they wanna treat that arg as different datatypes?
Excellent as always!
What puzzels me that it is possible to define an array of void pointers. That means that there must be a size of a void pointer otherwise indexing such an array would be difficult
Void pointers do have a size (all pointers have the same size). The problem with pointer arithmetic is that we don't know the size of the thing that the pointer points to.
@@JacobSorber clear, i get the point
What are your thoughts on the zig programming language
nice, I actually didn't know that's all UB
Good try to avoid UB ! However You still have ONE on the 22 line !)
Hey, could you do a video on AVL Trees, please?
We should talk more about hexspeak and what OSes uses it.
Cool! :)
You know, I'd always assumed that compilers wouldn't allow you to do void pointer arithmetic so I never thought to even try it. I mean as you said void doesn't have type information so you have no guarantees it would do anything remotely sane. But I guess compilers allowing you to do that is pretty C.
Would be cool to talk about TCC
What about sizeof(void)? What would that evaluate to?
It's a compile error as per C89. It's an incomplete type and u can't take the size of an incomplete type. Just like u can't take the sizeof a forward declared struct.
But gcc will compile it for you. And it will be equal to sizeof(char).
On GCC, sizeof(void) is typically 1. So, having the pointer arithmetic treat "+1" as "make the pointer point to the address 1 byte higher" is at least consistent with that.
(Edit: Ajinkya was faster, and more precise.)
Personally I think that since void is size 0 (as a result of no type info) pointer arithmetic with it should just result in addr + 0 * 2
That would kinda make sense, but GCC seems to define sizeof(void) as 1, so at least it's consistens there.
@@Uerdue That might be due to how it implements types under the hood, it might use division with it somewhere and to avoid checking for 0 they just default the size to 1, so in that sense I can understand it being 1 instead of 0
I think since C is an evolution of assembly code in the early days that most engineers saw an increment of an address/data as adding one. The exception were commands that would both load data and increment/decrement and address. These would do so according to the size of the data.
What's the worst bug you've ever faced? Is there one in particular that's memorable? I'd be interested to hear why you made it, and what steps you took to avoid repeating it. Maybe there's more than one?
Good question. I'll have to think about this one. Might be an interesting topic for a future video.
I've been developing uC products since my teens (I'm 46 now) I have a killer story which inspired this question, but I'm no youtuber.
@@michaelclift6849 Well, if you were to send it to a youtuber they might enjoy it and they might even include it in a video.
@@JacobSorber It may be difficult to include in a video, but here's what happened. Please confirm if you can access the link ok: drive.google.com/drive/folders/1pJGpEQ5IZGpaHYbHW4hzJ995pMUcP2PH?usp=sharing
I just wrote that exact comment on the other video then this video showed up for me 😂
how come sizeof(int*) = 8 but ip+2 increased by 8 instead of 2*8 ? (5:43)
The size of a pointer is the size of a word of memory, it will be 8 bytes for all 64-bit machines for any datatype you have a pointer to. The size of the datatype, that is the size when it would be dereferenced, in your case int, is 4. This is the case for any other datatype, just think about an array, any element is at offset i*sizeof(element[0]).
Because the +2 will look at the size of the pointed to type, which is the int in this case
@@stefan-danielwagner6597 Thanks for explanation, i get it now.
void* pointer arithmetic.
My god, who had this crazy idea in the first place?
Semantically it'd not defined at all. It should not compile, at least not without a warning.
Even with -Wall there is no warning. I guess he has to turn on -Wpedantic for that.
Would've been funny if it had been a nop instead, like void *v = &foo; v += 1; would equate to (void); and then be really weird and make dereferencing just return 0 every time. As in int i = *v; would result in i being set to 0 even if foo is an int and points to 47.
@@anon_y_mousse rather than define a behaviour that feel odd to most of us, it's better not to allow void* arithmetic in the first place.
@@unperrier5998 No, I meant comical funny, not odd funny. Especially if it issued no errors or warnings.
does not compile in c++
how to avoid structure padding?
Declare the struct with `__attribute__((packed))`.
@@Uerdue yes, but will affect the performance of the program
@@mihaeldimoski structure padding is there so that the cpu can be fast fetching memory, if the structure is not padded then cpu won't fetch memory fast, how do you want the cpu to fetch your structure fast if it's not padded correctly? simply not possible, you can't have it both ways
You can reorder your struct's members, look up the page "The Lost Art of Structure Packing"
There's no one way of doing it that's standard compliant. Using the __attribute__((packed)) method will work in GCC, but not in MSVC. However, one can use #pragma pack(push,1) before your struct and then #pragma pack(pop) after it to get the same behavior in both MSVC and GCC. In other compilers, it likely differs.
Hey, is carbon going to kill c?
nope! one of the reasons its an llvm language and not compiled into byte code
00:16 mister world wide
why dont you use clion
Why don't you use vim? 🤔 I have a video where I talk about IDEs. That might help clarify a bit. At some level, it's just personal preferences and what I think will be most helpful for my students.
Why on earth does C give the `+` operator this special, implicit, behaviour when it's operating on pointers? That just sounds like a recipe for confusion and bugs. Why doesn't C just say that pointers aren't valid arguments for arithmetic functions? This way, it would force you to treat addresses as ordinary unsigned integers with explicit casts, and then use `sizeof` to line up your arithmetic with the size of the objects being stored.
The main reason is alignment I believe.
Pointers to type T where T is a POD, must be aligned to sizeof(T) bytes.
int x = 0;
int *p = &x;
((char*)p) += 1;
*p = 10; //undefined behavior!
Assuming an _int_ is 4 bytes, *p* must have a value that is divisible by 4.
Functions like *memset* which use _long int_ pointers to access memory faster, must first make sure the pointer is divisible by *sizeof(long int)* and only then do the fast access (they access the unaligned bytes using a _char_ pointer).
So to avoid trivial bugs, addition on a pointer will not break the alignment. With your idea, compilers will probably issue warnings about alignment, which means people will use *sizeof* anyways, so why not make it a rule of the language anyways.
Because it happens often enough that people would be annoyed to have to write the additional `* sizeof(foo)` all the time.
Plus, it would make your code less maintainable. Because suddenly, when you try to use the same code for handling the "bar" type instead of "foo", you have to change the `sizeof(foo)` to `sizeof(bar)` everywhere... (And then you miss it one time and it makes for a very hard-to-find bug...)
One could maybe argue that having a *different* notation that is less prone to be confused with regular addition would be nicer. And in fact, there is one, namely `&(ptr[i])`. That's even more ugly, though... :D
@@monochromeart7311 What you're talking about with memset is an implementation detail that won't be shared with every implementation. With SSE it may access memory at offsets divisible by 16 bytes and even on 64-bit platforms it could still be implemented to deal with 1 byte at a time as the standard requires nothing more extravagant. Also, misaligned pointers aren't even necessarily slower on platforms that allow them which is most these days. Try this on your own computer: int a[3] = { 0 }; int *p = ( char * ) a + 5; *p = 123; // It's technically UB but will still compile and run without errors, though it should generate a warning, depending on the compiler you're using. And will actually generate an error if you set the right flags with your compiler.
@@anon_y_mousse the issue I'm talking about is UB due to misalignment, that's all.
All mem___ implementations I've seen work on word-sized memory for faster access (it's a common optimization), which is int/long on most platforms. The values at locations not divisible by the word size will be accessed using char pointers.
@@monochromeart7311 In this specific instance, it's possibly UB due to both misalignment and type mismatch due to the cast, and in other instances would certainly be both if you weren't just using int's, and I did say in my post that it's UB. However, it won't fail to execute and indeed correctly. Give it a try.
The real problem with understanding pointers is that people are coming from these languages that have a lot of abstraction
If you were a programmer in the early days and you come from assembly this will all make sense to you compared to a guy from js or python
Pointers: a heap of trouble
you are good professor but I really wish I can afford the C course, its a hundred dollars I am broke student.. I wish can be more affordable one course at a time for students.
There is plenty of online stuff to learn C for free. Code::Blocks is free and I use it for all my work.
@@JaimeWarlock Blocks? please send the proper channel I can follow there is thousands of them but only theory, not consistant.
In my years as a C programmer, I never used void*. It's one of a bunch of things in the C language that I never used, on principle. Because it's stupid.
You've never used malloc? Because that returns a void*