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...]

КОМЕНТАРІ • 110

  • @oneletterz1659
    @oneletterz1659 2 роки тому +46

    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.

    • @luz_reyes_676
      @luz_reyes_676 2 роки тому +2

      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)

    • @Yazan_Majdalawi
      @Yazan_Majdalawi Рік тому

      What does ECE stand for?

    • @oneletterz1659
      @oneletterz1659 Рік тому

      @@Yazan_Majdalawi electrical and computer engineering

    • @xr.spedtech
      @xr.spedtech Рік тому

      He's focusing on the basics ...
      There's other ground to cover outside basics.
      So other channels...
      To meet other needs.

  • @lonelymtn
    @lonelymtn 2 роки тому +2

    Thanks for shouting out to us here in the Southern Hemisphere!

  • @ramadhanafif
    @ramadhanafif 2 роки тому +4

    Your lessons has transformed my code, especially when it comes to optimization. Thanks a lot

  • @Byynx
    @Byynx Рік тому +1

    Superb i've learn for the first time what casting really means and even more about pointers. Thanks. ❤

  • @anon_y_mousse
    @anon_y_mousse 2 роки тому +7

    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.

    • @JacobSorber
      @JacobSorber  2 роки тому +2

      Thanks. I appreciate it.

    • @ramakrishna4092
      @ramakrishna4092 2 роки тому +1

      @@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 .

    • @herohera3497
      @herohera3497 Рік тому +1

      @@ramakrishna4092 what did u write if(1) just remove that function

  • @leokiller123able
    @leokiller123able 2 роки тому +8

    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

    • @francescomazzucco6264
      @francescomazzucco6264 2 роки тому +2

      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

    • @Uerdue
      @Uerdue 2 роки тому +2

      @@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...

    • @darioabbece3948
      @darioabbece3948 2 роки тому

      @@Uerdue I think sizeof(void) should be u64 since addresses are that long

    • @Uerdue
      @Uerdue 2 роки тому +5

      @@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.

    • @redcrafterlppa303
      @redcrafterlppa303 2 роки тому +1

      @@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) ;

  • @starc0w
    @starc0w 2 роки тому

    Great! Thank you very much!

  • @chrissaltmarsh6777
    @chrissaltmarsh6777 2 роки тому +1

    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.

  • @nieczerwony
    @nieczerwony 2 роки тому +2

    This is why I love C and low level. You shouldn't do it, but you are free to try. Full control.

    • @JacobSorber
      @JacobSorber  2 роки тому

      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.

  • @MoustafaRaafat2
    @MoustafaRaafat2 2 роки тому +4

    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.

  • @evan_game_dev
    @evan_game_dev 2 роки тому

    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

  • @redcrafterlppa303
    @redcrafterlppa303 2 роки тому +4

    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.

    • @JacobSorber
      @JacobSorber  2 роки тому +4

      You're welcome. Glad I could help.

  • @insu_na
    @insu_na Рік тому

    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

  • @laxmikantbotkewar4191
    @laxmikantbotkewar4191 2 роки тому +3

    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.

  • @abdallahmah1867
    @abdallahmah1867 Рік тому

    will get it. Just don't get burnt out. Whenever you need a break, take one.

  • @Byynx
    @Byynx Рік тому

    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?

  • @keesterwee4890
    @keesterwee4890 2 роки тому

    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

    • @JacobSorber
      @JacobSorber  2 роки тому +3

      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.

    • @keesterwee4890
      @keesterwee4890 2 роки тому

      @@JacobSorber clear, i get the point

  • @codegodtreviso4448
    @codegodtreviso4448 2 роки тому

    What are your thoughts on the zig programming language

  • @nexovec
    @nexovec 2 роки тому +2

    nice, I actually didn't know that's all UB

  • @viacheslav1392
    @viacheslav1392 2 роки тому +1

    Good try to avoid UB ! However You still have ONE on the 22 line !)

  • @marcotulioalvesdebarros518
    @marcotulioalvesdebarros518 2 роки тому

    Hey, could you do a video on AVL Trees, please?

  • @georgecop9538
    @georgecop9538 2 роки тому

    We should talk more about hexspeak and what OSes uses it.

  • @nexasdf
    @nexasdf 2 роки тому

    Cool! :)

  • @beardlyinteresting
    @beardlyinteresting Рік тому +1

    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.

  • @georgecop9538
    @georgecop9538 2 роки тому

    Would be cool to talk about TCC

  • @SlideRSB
    @SlideRSB 2 роки тому +3

    What about sizeof(void)? What would that evaluate to?

    • @ajinkyakamat7053
      @ajinkyakamat7053 2 роки тому +3

      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).

    • @Uerdue
      @Uerdue 2 роки тому +2

      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.)

  • @zxuiji
    @zxuiji 2 роки тому +3

    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

    • @Uerdue
      @Uerdue 2 роки тому +1

      That would kinda make sense, but GCC seems to define sizeof(void) as 1, so at least it's consistens there.

    • @zxuiji
      @zxuiji 2 роки тому +1

      @@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

    • @JaimeWarlock
      @JaimeWarlock Рік тому

      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.

  • @michaelclift6849
    @michaelclift6849 2 роки тому +1

    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?

    • @JacobSorber
      @JacobSorber  2 роки тому

      Good question. I'll have to think about this one. Might be an interesting topic for a future video.

    • @michaelclift6849
      @michaelclift6849 Рік тому

      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.

    • @JacobSorber
      @JacobSorber  Рік тому +1

      @@michaelclift6849 Well, if you were to send it to a youtuber they might enjoy it and they might even include it in a video.

    • @michaelclift6849
      @michaelclift6849 Рік тому

      @@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

  • @Sakuraigi
    @Sakuraigi 6 місяців тому

    I just wrote that exact comment on the other video then this video showed up for me 😂

  • @maqusss
    @maqusss 2 роки тому

    how come sizeof(int*) = 8 but ip+2 increased by 8 instead of 2*8 ? (5:43)

    • @stefan-danielwagner6597
      @stefan-danielwagner6597 2 роки тому +3

      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]).

    • @sanderbos4243
      @sanderbos4243 2 роки тому +2

      Because the +2 will look at the size of the pointed to type, which is the int in this case

    • @maqusss
      @maqusss 2 роки тому

      @@stefan-danielwagner6597 Thanks for explanation, i get it now.

  • @unperrier5998
    @unperrier5998 2 роки тому +2

    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.

    • @ohwow2074
      @ohwow2074 2 роки тому +1

      Even with -Wall there is no warning. I guess he has to turn on -Wpedantic for that.

    • @anon_y_mousse
      @anon_y_mousse 2 роки тому

      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.

    • @unperrier5998
      @unperrier5998 2 роки тому

      @@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.

    • @anon_y_mousse
      @anon_y_mousse 2 роки тому

      @@unperrier5998 No, I meant comical funny, not odd funny. Especially if it issued no errors or warnings.

    • @justcurious1940
      @justcurious1940 Рік тому

      does not compile in c++

  • @mihaeldimoski
    @mihaeldimoski 2 роки тому +1

    how to avoid structure padding?

    • @Uerdue
      @Uerdue 2 роки тому +2

      Declare the struct with `__attribute__((packed))`.

    • @mihaeldimoski
      @mihaeldimoski 2 роки тому +1

      @@Uerdue yes, but will affect the performance of the program

    • @mohad12211
      @mohad12211 2 роки тому +4

      @@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

    • @sanderbos4243
      @sanderbos4243 2 роки тому +4

      You can reorder your struct's members, look up the page "The Lost Art of Structure Packing"

    • @anon_y_mousse
      @anon_y_mousse 2 роки тому +1

      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.

  • @18bansalaman
    @18bansalaman 2 роки тому

    Hey, is carbon going to kill c?

    • @emiliachan
      @emiliachan 2 роки тому +3

      nope! one of the reasons its an llvm language and not compiled into byte code

  • @olafgunther9401
    @olafgunther9401 Рік тому

    00:16 mister world wide

  • @didiTchu
    @didiTchu Рік тому

    why dont you use clion

    • @JacobSorber
      @JacobSorber  Рік тому +1

      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.

  • @gloverelaxis
    @gloverelaxis 2 роки тому +1

    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.

    • @monochromeart7311
      @monochromeart7311 2 роки тому +1

      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.

    • @Uerdue
      @Uerdue 2 роки тому +1

      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

    • @anon_y_mousse
      @anon_y_mousse 2 роки тому

      @@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.

    • @monochromeart7311
      @monochromeart7311 2 роки тому

      @@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.

    • @anon_y_mousse
      @anon_y_mousse 2 роки тому

      @@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.

  • @rubyciide5542
    @rubyciide5542 7 місяців тому

    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

  • @luciuscato4859
    @luciuscato4859 Рік тому

    Pointers: a heap of trouble

  • @lissettevelec8718
    @lissettevelec8718 Рік тому

    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.

    • @JaimeWarlock
      @JaimeWarlock Рік тому

      There is plenty of online stuff to learn C for free. Code::Blocks is free and I use it for all my work.

    • @lissettevelec8718
      @lissettevelec8718 Рік тому

      @@JaimeWarlock Blocks? please send the proper channel I can follow there is thousands of them but only theory, not consistant.

  • @saumyacow4435
    @saumyacow4435 Рік тому

    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.