Issues with the pre- and postincrement operator in C, C++, etc.

Поделиться
HTML-код
  • Опубликовано: 20 дек 2021
  • Patreon ➤ / jacobsorber
    Courses ➤ jacobsorber.thinkific.com
    Website ➤ www.jacobsorber.com
    ---
    Issues with the pre- and postincrement operator in C, C++, etc. // The pre- and post-increment operators cause a lot of new programmers some headaches, because they forget that they are both a statement and an expression. This video helps break things down.
    Related Videos:
    Make: • Learn make in 60 seconds.
    ***
    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...]

Комментарии • 70

  • @stephenaustin3026
    @stephenaustin3026 2 года назад +20

    This is fine for situations where you're dealing with simple types, and in C. But in C++ with iterator objects (or other instances of other classes which overload operator++()) the post increment/decrement operators might cause a copy to be constructed, which could be costly.

  • @RAINE____
    @RAINE____ 2 года назад +31

    Lovely video. Perhaps you could cover order of evaluation. For example, var[i] = var[++i] is not the same as var[i] = var[i+1]

    • @billowen3285
      @billowen3285 2 года назад +1

      Yeah I thought he would too, that one got me good when I stumbled across it

    • @ianmathwiz7
      @ianmathwiz7 2 года назад +12

      IIRC, if you read a value twice and also write that value in the same expression (as you do in the first expression), it's actually undefined.

    • @RAINE____
      @RAINE____ 2 года назад +1

      @@ianmathwiz7 Nice point! Good knowledge

    • @shan3722
      @shan3722 2 года назад +8

      Relying on order of evaluation invokes unspecified behavior (note that this is different from undefined behavior).
      From *The C Programming Language, Second Edition* _Section 2.12_ "Precedence and Order of Evaluation":
      "C, like most languages does not specify the order in which the operands of an operator are evaluated. (The exceptions are &&, ||, ?:, and ','.) ... Intermediate results can be stored in temporary variables to ensure a particular sequence."
      Same goes for function arguments:
      "Similarly, the order in which function arguments are evaluated is not specified"
      For more information, I suggest looking into sequence points.

    • @marcelocosta9620
      @marcelocosta9620 2 года назад

      Unspecified behavior. The compiler don't know what exactly will happen and warn it to you.

  • @cameronball3998
    @cameronball3998 2 года назад +2

    Wish someone taught me this in my early days in university... I never understood this during any of my intro coding classes. Great explanation. Will definitely refer people who I see with this problem to this video.

  • @JustinCromer
    @JustinCromer 2 года назад

    Some truly beautiful and simple examples of programs using this to the max in K&R

  • @patrykmielczarek3981
    @patrykmielczarek3981 2 года назад

    I really enjoy your videos. Even as an advanced programmer I stil learn new interesting facts through your videos. Keep going

  • @saeedmahmoodi7211
    @saeedmahmoodi7211 2 года назад

    Happy new year sir and please continue C server series🙏

  • @RileyCourter
    @RileyCourter 2 месяца назад

    Thank you so much for this video! You rock!

  • @fuemedicalcenter
    @fuemedicalcenter 2 года назад

    definitely one of the problems when you start with pointer artimetics is this pre and post increment of values, which can get quite confusing. Excellent topic!

  • @rafalmichalski4893
    @rafalmichalski4893 2 года назад +3

    Hello Jacob. You could cover order of function's arguments evaluation. This is improved with C++17 standard.

  • @ahmadalastal5303
    @ahmadalastal5303 2 года назад +2

    Good video for beginners, but it is not just about how people like to write it, it is much deeper than this, the increment operator is actually a CPU inc instruction for both x86 and x64 and it could be atomic operation when using atomic increment/decrement, X++ is not the same as X = X + 1 when talking about atomic operations, X = X + 1 contains 3 different operations (read-modify-write) that could be intercepted by some other thread in the program where atomic increment/decrement can not, X++ is generally faster than X = X + 1 because of the way inc instruction works, CPU optimizes this commonly used instruction to be faster than read from memory and add 1, like below for x64:
    Increment proc
    mov rax, dword ptr[rsp]
    add rax, 1
    ret
    Increment endp
    ; With faster inc instruction:
    IncrementWithInc proc
    inc rax
    ret
    IncrementWithInc endp
    Another example where ++X is faster than X++ is the loops, take this example
    for (int x = 0; x < 5; x++) {} // Slower
    for (int x = 0; x < 5; ++x) {} // Faster
    The first one will increment the value of X save it in temporary variable read X, while the second one says increment the value of X and directly move on without any intermediate stages, today compilers are smart enough to optimize the slower version and replace it with the faster version.
    Keep up the good work

    • @RockTo11
      @RockTo11 2 года назад +1

      "...today compilers are smart enough to optimize the slower version and replace it with the faster version" - it is important to write code which shows the programmer's intent. Specificity is important, so even if i++ and ++i result in the same instructions, just write is as you intend for the machine to execute it.

  • @TranscendentBen
    @TranscendentBen 2 года назад

    What this video does NOT mention is incrementing iterators. Using integers, the "standard" for loop is for (i = 0; i < n; i++) but I've read where iterators should use the preincrement, for (i = 0; i < n; ++i) but I forget exactly why. I vaguely recall it has something to do with it being more efficient or some such, BUT how could that be? The effect is the same - the compiler should recognize that the thing is incremented by one, and the value is not used in any immediate expression, so preincrement vs. postincrement doesn't matter.
    This is just one of many areas where C++ is MUCH more complicated than C.

    • @Swedishnbkongu
      @Swedishnbkongu 2 года назад

      Lol don't tell the compiler what it "should" do. The reason for that advice you may have been given is not because of some quirk in the C++ language:
      For *iterators* we could be talking about any class type, not necessarily a cheap integer or pointer. The you can only do "++i" or "i++" on an 'iterator' because we assume they overloaded the pre/post increment operators, which are *functions*. This means to use them, the compiler must generate a function call, even if it's inlined during optimization. The compiler has no guarantees that the way you/a library dev have implemented those functions is identical except for evaluation order/copying, so if you call the post increment operators, the compiler almost certainly must call your user-defined post-increment operator rather than pre-increment. And to correctly implement a post-increment, you almost certainly will have a copy being made of the original iterator (to hold the not-yet-incremented state, then increment it, then return the old copy). So by calling post-increment without needing it, you are forcing the compiler to call a function that makes a useless copy which you discard. This might be expensive, and cannot be optimized out unless the compiler proves it is trivial and has no side effects or exception guarantees, which is sometimes difficult or impossible.

  • @kamertonaudiophileplayer847
    @kamertonaudiophileplayer847 2 года назад

    Indeed, I even made a post regarding this. Dori did something like "return n++;" expecting that a returned value will be n+1. No, the returned value will be still n. She should do "return ++n;" as you explained. Or just return n+1 in case of a hesitation.

  • @basicduck
    @basicduck 2 года назад +1

    Hey, uhh I didn’t go to college so I don’t have the full-spectrum of CS. I’ve been programming for about 5 years for client-side and building micro services/server programs. Do you have any book recommendations for what you are teaching? The lowest level I’ve worked on was Java for android devices/servers.

  • @leonm8906
    @leonm8906 2 года назад +1

    I guess it's supposed to be "the output is the same but it is still a 1 up on c" since it adds in higher level features like classes while also promising low level control like c does.

  • @mrcrackerist
    @mrcrackerist 2 года назад +2

    A horrible way to ship even or odd numbers is to use ++x++ :P

  • @IamTheHolypumpkin
    @IamTheHolypumpkin 2 года назад +4

    I never knew the ++ had a name. I always called it the ++ operator.
    I tend to use ++i, because my programming teacher said in the far back it used to be slightly faster then i++. I doubt that there is any performance difference nowadays.
    I try to switch to i+=1 like it is in python and swift just to make ne not remember two different ways.

    • @DaNinjasDen
      @DaNinjasDen 2 года назад +3

      The performance difference is a real thing, but it's only really noticable for types wuth an expensive copy. The post-increment creates a copy while pre does not

    • @godowskygodowsky1155
      @godowskygodowsky1155 2 года назад

      @@DaNinjasDen Shouldn't compilers these days be smart enough to optimize this away?

    • @DaNinjasDen
      @DaNinjasDen 2 года назад

      @@godowskygodowsky1155 it is actually necessary in some instances (hence why the feature exists). For primative types you wont notice the performance difference unless you are hyper optimising in which case you'd be aware of it. Fpr custom types (where the copy matters) you need to write the method yourself so you should know which one has the copy and which one doesn't, and use it appropriately. For all I know the compiler may be able to optimise it in some cases but I haven't looked into it

  • @cezzar5233
    @cezzar5233 2 года назад +1

    Int X=1, y=2, c;
    C=x+++y;
    What will be the value of c and x when they are printed?? And why?

    • @Swedishnbkongu
      @Swedishnbkongu 2 года назад +1

      Is this a quiz or an actual question? C lexical analysis is greedy, so the pluses would be ++ and +, making it (x++)+(y), which is 3, since the expression x++ is 1

  • @sansho88
    @sansho88 2 года назад

    Hello Jacob, this increment method is interesting, even when we use it for a while it's good to come back on again about how exactly they work :)
    Btw, I like how you introduce these subjects, that's why I'd really appreciate if you can explain me how signals between 2 programs work (with and without fork() :p )
    And have a merry Christmas :)

    • @casperes0912
      @casperes0912 2 года назад +1

      You mean regular Unix/Posix signals like SIGHUP, SIGKILL, SIGINT, etc.?
      If so, it's mostly a kernel feature and doesn't really much matter if you do it to a forked process or not. When you register a signal handler you make a sys call that gives the kernel a function pointer to your handler to associate with that signal. When you send a signal to a process the kernel looks up if there's a handler for the process, if there is, it sets the instruction pointer to it, if not it kills the process (depending on signal - might also do nothing). That's about it

    • @sansho88
      @sansho88 2 года назад

      @@casperes0912 Mmh thanks for you explanation!
      Well, my bad, I havn't see this gem (even if I searched it before...):
      ruclips.net/video/83M5-NPDeWs/видео.html

  • @airjuri
    @airjuri 2 года назад +1

    And back in the day before great optimizations on compilers ++i was faster than i++ if you just used it for incrementing a counter. Beacause of that i still use post increment when using something just for counters, even in other languages :D

  • @basalticlife1861
    @basalticlife1861 2 года назад

    Simple but interesting.

  • @rogo7330
    @rogo7330 2 года назад

    [Post/pre]increments are nice to write more cleaner code, like for example
    instead of
    if ((x = x+1) > LENGHT(array)) break;
    i can type only this
    if (++x > LENGHT(array)) break;
    There is a lot of use for this syntax sugar. I also like `?:` conditional operator because i can just place what could be a several lines of `if-else` statement to one line, if it short enough and i still wanna do it in one line of course :)

  • @guilherme-freire
    @guilherme-freire 2 года назад

    Nice video. There is one thing I am a little confused about this: usually I use i++ inside for loops, but I've seen some people using ++i instead, why is that? I imagine it is preference and it actually does not matter but idk

    • @redjr242
      @redjr242 2 года назад +3

      Before optimizing compilers, it was slightly faster to do ++i for integers, but not really the case anymore. Where it does matter today is iterators and custom class that implement ++i. I think it is easier to implent, and doesn't required a copy that a post increment would need. This is why the template libraries only ever use ++i in for loops: it works for more types. I think it's bad practice to mutate and access a variable in one line so I personally would never use post increment anywhere. This also makes it easier to read and write code because it is one fewer thing to think about: did this person actually intend to use post increment, or is this a case where it doesn't matter?

  • @mateuszmasalski7722
    @mateuszmasalski7722 2 года назад

    Ok if some wouldn't do something like printf(%d,++i), i would prefer to increment value before and print it before code like that only bring confusion

  • @rustycherkas8229
    @rustycherkas8229 2 года назад

    Application? A LIFO stack:
    int stack[ somesize ], sp = 0;
    void push( int val ) { stack[ sp++ ] = val; }
    int pop( void ) { return stack[ --sp ]; }
    int stackHeadroom( void ) { return somesize - sp; }
    Add bounds checking to suit.
    // I wanted to get another "headroom" reference into another comment, Max 🤣🤣

  • @joeedh
    @joeedh 2 года назад

    Is this really something that trips people up? I mean it's not as bad as, say, for (i=0; i

  • @Stomachbuzz
    @Stomachbuzz 2 года назад

    Honestly, I think super small details like this are more trouble than they're worth.
    I've read about the pre/post-fix thing 3 or 4 times now. And every time I'm just like "...but why though??"

  • @eprohoda
    @eprohoda 2 года назад

    like~this is otustanding video-work- 😊

  • @rmaster934
    @rmaster934 2 года назад +1

    C# has post-increment operators twice!
    C++
    _++
    Although this doesn't actually compile in C, so you should do (C++)++ or smth

    • @patryk_49
      @patryk_49 2 года назад

      It doesn't compile in C because the postincrement doesn't return a variable you've incremented, but instead it returns it's copy.
      This copy is an r-value, that means it cannot be modified.

  • @Qosm0s
    @Qosm0s 2 года назад

    How would following work? Is second parameter x + 1?
    foo(x++, x++)

    • @mgx9383
      @mgx9383 2 года назад

      Probably undefined.

    • @rmaster934
      @rmaster934 2 года назад +1

      Undefined behavior, but probably you would get foo(x+1, x) for Windows iirc? (Still, UB)

    • @shan3722
      @shan3722 2 года назад

      @@rmaster934 technically unspecified behavior*
      invoking unspecified behavior _may_ not be a problem if you're not worried about portability
      invoking undefined behavior is always a bad idea

    • @rmaster934
      @rmaster934 2 года назад

      @@shan3722 uh yeah i kinda mixed up with i++ + ++i..

  • @LoesserOf2Evils
    @LoesserOf2Evils 2 года назад +1

    Good grief! No wonder I keep tripping up post-decrement/increment and pre-decrement/increment. Yes, a further discussion would help.
    Many thanks!

  • @vk6297
    @vk6297 2 года назад

    if anyone has any documentation of nach operating system please provide.And if anyone has done a project in implementing system call of any basic os please guide me.

  • @GooogleGoglee
    @GooogleGoglee 2 года назад

    Can you make new videos about the make file from the basis? In a simpler way

    • @JustinCromer
      @JustinCromer 2 года назад

      It helps if you study a little bit of bash scripting on your own, then the make syntax becomes incredibly intuitive

    • @GooogleGoglee
      @GooogleGoglee 2 года назад

      @@JustinCromer do you reccomend any sources?

  • @gldkrn
    @gldkrn Год назад

    int x =1;
    x=x++
    pf(x)
    What would happen here

  • @unperrier5998
    @unperrier5998 2 года назад

    I like your theory about ++C instead of C++
    Makes sense, not in a merketing sense, though.

  • @Sadi000Q
    @Sadi000Q 2 года назад

    Wow...I was really hoping to learn why people use i++ or ++i in for() loops :( Maybe in a future video or something?

    • @auz7977
      @auz7977 2 года назад

      the reason you see i++ and ++i in for loops is because for loops very often have a counter variable that the loop increments/decrements each iteration, and using i++/++i is just a quick way to write it. it would work the same if you did "for (int i=0; i

    • @nunyobiznez875
      @nunyobiznez875 2 года назад +1

      ​@@auz7977 Yes, it's still applicable to modern systems. The difference is small, but ++pre generally uses fewer instructions and in some cases, less memory. Any optimizing compiler worth it's salt, should make the optimization where it can though, so it shouldn't matter much in most cases. However, I prefer not relying on the hope that compiler optimizations will do something so simple for me, when I can be certain just by doing it myself in the first place, with no extra effort. It's even easier, to just make a habit of using pre-increment in the cases where ++either++ will do. But, I guess like most things, it largely boils down to preference.

  • @dzious
    @dzious 2 года назад

    Great video for beginners thanks for that.
    I think a good followup video would be to add the += / -= operator and look at the assembly code it generates. This way people would even more understand how it works.
    Of course this is just my opinion
    Once again thanks for your videos. Have a great day !

  • @Qbe_Root
    @Qbe_Root 2 года назад

    so basically, C++ is just C, but after you learn it, C looks better by comparison?

  • @AlexJacksonSmith
    @AlexJacksonSmith 2 года назад

    "--C"?

  • @ohwow2074
    @ohwow2074 2 года назад

    Oh Yes. I like ++C. 😄

  • @rogo7330
    @rogo7330 2 года назад

    C+=1 :D

  • @mgx9383
    @mgx9383 2 года назад

    C++ means it _will_ get better than C _eventually_ .

  • @kissgergo5202
    @kissgergo5202 2 года назад

    I'm gonna start calling c++ ++c

  • @jgcooper
    @jgcooper 2 года назад

    I hate this operator and make an effort to never use it.
    It's only use is to make code less readable.

  • @aliobeid
    @aliobeid 2 года назад

    Please, please ditch the intro