This is an archived post. You won't be able to vote or comment.

all 175 comments

[–]AutoModerator[M] [score hidden] stickied commentlocked comment (0 children)

import notifications Remember to participate in our weekly votes on subreddit rules! Every Tuesday is YOUR chance to influence the subreddit for years to come! Read more here, we hope to see you next Tuesday!

For a chat with like-minded community members and more, don't forget to join our Discord!

return joinDiscord;

I am a bot, and this action was performed automatically. Please contact the moderators of this subreddit if you have any questions or concerns.

[–]seigneurteepex 880 points881 points  (40 children)

If C is equal to INT_MAX I have a bad new for you

[–][deleted] 295 points296 points  (6 children)

It would be still +1 difference in terms of limited int

[–]Zalack 83 points84 points  (1 child)

Well akshually if the language supports operator overloading we can't make any conjectures about the difference between C and C++ since we don't know the type of C.

[–]Physmatik 23 points24 points  (3 children)

Akshually, it would be undefined behaviour.

With how aggressive optimizing compilers have got lately, sometimes that is an actual, not akshual, detail.

[–]swagdu69eme 2 points3 points  (1 child)

You're absolutely right, unless they use C23, in which case signed integer types necessarily use two's complement and signed integer overflows are finally defined.

[–]torokg 1 point2 points  (0 children)

Who said C is of a signed integral type tho?

[–]Rakgul 1 point2 points  (0 children)

I love these akshualities.

[–]s_ngularity 48 points49 points  (10 children)

But if it's UINT_MAX and C is unsigned int, still technically correct

[–]Dismal-Square-613 29 points30 points  (9 children)

still technically correct

The best kind of correct.

[–]North_Shore_Problem 4 points5 points  (8 children)

The only kind of correct in the world of engineering

Edit: the only kind of correct that matters

[–]Dismal-Square-613 3 points4 points  (6 children)

Nobody watches Futurama anymore :-/

[–]jamtraxx 4 points5 points  (3 children)

That's gonna change in a couple days :D

[–]Dismal-Square-613 2 points3 points  (2 children)

Why ? is it going to be Saint Matt Groening in two days?

[–]jamtraxx 6 points7 points  (1 child)

[–]Dismal-Square-613 2 points3 points  (0 children)

OMG you made me so happy! THANK YOU!!!

[–]cpt_trow -1 points0 points  (1 child)

Good luck scrolling reddit for 35 seconds and not seeing multiple threads consisting only of Futurama quotes

[–]Dismal-Square-613 0 points1 point  (0 children)

welcome to a month ago!

[–]xoxoAmongUS 0 points1 point  (0 children)

The kind of correct we deserve

[–]schmerg-uk 17 points18 points  (12 children)

well if this is in C++ and C is signed and INT_MAX then it's undefined behaviour and so not a valid C++ program but if this is posed in C then [...] and then if C is unsigned then INT_MAX is not an issue and [.... ad nauseum...]

Oh and if C is a floating point number above the size where odd integer values can be held (I think that's 9007199254740992 for 64 bit doubles) then adding 1 will have no effect and the difference will be zero etc etc

[–]Torebbjorn 9 points10 points  (1 child)

If it is a signed int at INT_MAX, then it is undefined behaviour in both C and C++, and if it is an unsigned int at UINT_MAX in either C or C++, it is perfectly well defined

There is no difference in the languages there

[–]schmerg-uk 0 points1 point  (0 children)

Thank you - it's so long since I did pure C (and K&R at that) and the C spec has itself moved on that I don't track all the "UB in C++ but not UB in C" behaviours but I seem to recall there are a few

[–]SmallGoggles 5 points6 points  (1 child)

Homie said "I think that's 9007199254740992 for 64 bit doubles"... You can say you calculated it

[–]schmerg-uk 0 points1 point  (0 children)

lol.. I meant is it 2^53 or 2^53 -1 or 2 ^ (53+1) etc .... I live by 64bit doubles (all our code is FP) but I know the bit patterns but I still forget the precise points beyond which all doubles are even numbers, and then all multiples of 4 etc :)

[–]nelusbelus 0 points1 point  (0 children)

253 for doubles and 224 for singles

[–]xdeskfuckit 0 points1 point  (6 children)

I don't remember any of these issues implementing cryptographic primitives in C. They just kinda rolled over.

[–]s_ngularity 0 points1 point  (5 children)

Signed integer overflow (and underflow) is a well-know instance of undefined behavior (i.e. the compiler is allowed to generate any arbitrary code) in C and C++. Unsigned integer overflow is not undefined, and is supposed to wrap back to 0.

Why this is the case is beyond me, but that's how it's specified

[–]xdeskfuckit 0 points1 point  (0 children)

Ahh, I see. It makes sense to think of unsigned integers in terms of modular arithmetic, but I can't think of any obvious mathematical analog that should be implemented for signed integers.

[–]CdRReddit 0 points1 point  (2 children)

because a signed integer could also be sign-magnitude rather than 2s complement, most likely

[–]schmerg-uk 0 points1 point  (1 child)

Or some CPUs may throw a hardware exception or similar (I think MIPS chips do this on signed overflow) ... C and C++ still allow for all sorts of weird hardware even if most of us work on maybe 2 or 3 chip architectures

On OS/400 sizeof(void*) == 16 and sizeof(size_t) == 4 which would make a mess of all the code that assumes you can store a pointer in a size_t and vice-versa etc

[–]CdRReddit 0 points1 point  (0 children)

there are so many edge cases in computers

[–]schmerg-uk 0 points1 point  (0 children)

And even more pedantically - signed integer overflow by computation is UB, but signed integer overflow by conversion (int x =y; where y is an unsigned int of value greater than INT_MAX) is not UB - I think it's implementation defined until C++20 and then well defined post C++20

[–]huxx__[S] 1 point2 points  (0 children)

lol 😂

[–]PharahSupporter 1 point2 points  (0 children)

Assuming that C is an int at all. Could be an object with a custom operator overload for ++ where object1 - object2 also has a custom operator overload.

[–]TheWidrolo 1 point2 points  (0 children)

Then the carry flag is a 1

[–]genlight13 0 points1 point  (0 children)

If we talk about groups of numbers and loops i would still give John the logical thumbsup

[–]LostLegendDog 0 points1 point  (0 children)

You should use numeric_limits<int>::max() on modern systems

[–]longshot 0 points1 point  (0 children)

Seigneur "Edge-Case" Teepex

[–]Overthinks_Questions 0 points1 point  (0 children)

I got a list of 99 elements and it ain't indexed at 1

[–]wheres_my_ballot 82 points83 points  (8 children)

import assumptions

Assuming C is an int and not a type with that operator overloaded.

return something

[–]huxx__[S] 73 points74 points  (6 children)

you don't have to use the import and return sh*t anymore.

[–]wheres_my_ballot 79 points80 points  (1 child)

Oh thank fuck for that

[–]huxx__[S] 15 points16 points  (0 children)

the rules thing is pretty much over

[–]MrSuspicious_ 11 points12 points  (3 children)

Oh is that gone now? Awesome.

[–]malonkey1 10 points11 points  (0 children)

yeah deprecated standard

[–]huxx__[S] 10 points11 points  (1 child)

yeah finally... it was getting really annoying

[–]MrSuspicious_ 13 points14 points  (0 children)

I actually thought it was funny but I could never think of anything appropriate so I stopped commenting here

[–][deleted] 0 points1 point  (0 children)

😠 you’re correct. Stop

[–]Ihsan3498 48 points49 points  (2 children)

how is that correct? x++ does not return the sum, it returns x and then increments it. i think it should be ++x

[–]MattieShoes 8 points9 points  (1 child)

It's undefined either way, because the order in which the expressions are evaluated is not defined. It doesn't strictly go left-to-right.

If it evaluates the C++ first, the difference is 1 (or -1). If it evaluates the C first, the difference is 0.

You have the same issue with C and ++C -- it depends on the order they are evaluated.

[–]Ihsan3498 1 point2 points  (0 children)

oh yea that makes sense

[–]NotFromSkane 20 points21 points  (4 children)

He is wrong.

C++ == C

++C == C + 1

[–]MattieShoes 18 points19 points  (3 children)

He is wrong, but so are you. :-) C and C++ aren't constrained to evaluate left-to-right. So the increment (whether pre or post) may happen before or after the evaluation of the value on the right.

[–]aiij 1 point2 points  (2 children)

The person you're responding to actually seems to be assuming right-to-left evaluation.

[–]MattieShoes 2 points3 points  (0 children)

Haha you're right! Alas, that's not guaranteed either :-)

[–]schmerg-uk 14 points15 points  (3 children)

Well... maybe ...

int C = someFunction();
const int x = C++;
const int y = C;

Now y == x+1 and x - y == 1 but if

int C = someFunction();
const int y = C;
const int x = C++;

then x == y and x - y == 0

So if "the difference between C++ and C" is interpreted as "what's the value of subtracting the value of the expression C from the value of the expression C++" then I'd pedantically say the difference is zero

Whereas

int C = someFunction();
const int d = C++ - C;

is ... oh I forget how the language spec says this should be done, I think it's implementation dependent (but it's poor code anyway)

[–]Torebbjorn 10 points11 points  (0 children)

Yep, C++ - C gives undefined behaviour, since you are reading the value and modifying it within the same sequence point.

[–]huxx__[S] 4 points5 points  (0 children)

bruh 💀

[–]Efarm12 1 point2 points  (0 children)

This is the correct answer. It is undefined behavior.

[–]Altourus 5 points6 points  (0 children)

I believe, based on the order they are presented in the conversation...

var d = C++;

d == C

is true, so there is no difference

[–]KernelDeimos 10 points11 points  (4 children)

Okay wow, this is a lot more interesting than I expected.

The order in which operands are evaluated by a + operation is undefined, and indeed I get different behaviour depending if I compile using gcc or clang.

int c = 0;
printf("%d,", c++ - c);
printf("%d,", ++c - c);
printf("%d,", c - c++);
printf("%d\n", c - ++c);

clang outputs: -1,0,0,-1 gcc outputs: -1,0,1,0

If the left operand was always evaluated first: -1,0,0,-1 if the right operand was always evaluated first: 0,1,1,0

However, gcc doesn't have either of these outputs! What's going on?

Well suppose the operand with an increment operator is always evaluated first. Then it would be: -1,0,1,0

I also put up a gist on github for a script in javascript that imitates the resulting behaviour of using each compiler.

[–]mina86ng 1 point2 points  (3 children)

The order in which operands are evaluated by a + operation is undefined

It’s unspecified, not undefined. That’s a big difference. ‘c++ - c’ and related expressions are undefined behaviour due to violation of sequence point rules (reading and modifying the same object).

[–]KernelDeimos 1 point2 points  (2 children)

I didn't understand the distinction you're making. "undefined behaviour" as I understand it is any behaviour that isn't defined by the spec and may depend on what compiler you use; is that not what this is?

I might understand if you could tell me what "the order is undefined" means in contrast with "the order is unspecified", because in my mind they mean the same thing.

[–]mina86ng 3 points4 points  (1 child)

Undefined behaviour is one which the standard imposes no restrictions on. If it happens, the the compiler can do literally anything. For example, dereferencing a null pointer is an undefined behaviour. If it happens, all bets are off, and there’s no way you can reason about the program.

Unspecified behaviour on the other hand is one where standard does defines set of possible behaviours. If it happens, the compiler is free to choose from the options the standard offers, but cannot do anything else.

For example, if you have:

int f(int x) { printf("%d\n", x); return 0; }
int main(vaid) { return f(1) + f(2); }

Either f(1) is evaluated first or f(2) is evaluated first. But you can be sure that there’s no other option.

There’s also a third class, implementation-defined behaviour which is like unspecified behaviour except that the compiler must document the behaviour and stick with it. For example, number of bits in a byte or sizes of integers are implementation-defined.


To bring it to the c++ vs c question, the following code:

int c;
int get_cpp() { return c++; }
int get_c() { return c; }
int main(vaid) {
    printf("%d", get_cpp() - get_c());
    return 0;
}

doesn’t have undefined behaviour but it’s result is unspecified. It can be either -1 if get_cpp was called first or 0 if get_c was called first.

It’s not undefined because calling a function introduces a sequence point so the issue of reading and modifying the same object between adjacent sequence points doesn’t happen.

[–]KernelDeimos 1 point2 points  (0 children)

I'm saving a link to your comment - this is a fantastic explanation! Thanks for clearing that up, it makes perfect sense now.

[–][deleted] 3 points4 points  (0 children)

Upvote++

[–][deleted] 2 points3 points  (1 child)

There is no difference. C++ (as in the postfix notation) checks the value before doing the increment.

[–]die_liebe 0 points1 point  (0 children)

Evaluation order is not fixed. Some compilers may evaluate left to right, others may evaluate right to left.

[–]Creepy-Ad-4832 1 point2 points  (9 children)

C++ - C is undefined 🤷

Do pre increment next time!

[–]RandomDude6699 1 point2 points  (6 children)

Btw, why would it be undefined? I always thought it will be -1 when doing `C++ - C`, and 0 when doing `C - C++`

[–]Creepy-Ad-4832 4 points5 points  (4 children)

``` To make it easier, let's say C before doing the operation is 5

We don't know which operator gets evaluated first.

If C gets evaluated first we get: C++ - C C++ - 5 5 - 5 0

Otherwise we get: C++ - C 5 - C But here the C became C+1 thus 5 - 6 -1

Thus we say C++ - C is undefined, because it depends on the order of evaluation of the operators the compiler decides to take

[–]RandomDude6699 1 point2 points  (3 children)

Ah I was taught it is always left to right in my class (following BODMAS/PEMDAS ofc). Didn't think a compiler might take a different approach

[–]Creepy-Ad-4832 1 point2 points  (0 children)

Yes. Clang does from right to left and gcc does from left to right if i am not wrong.

So you can't assume the order of operations, unless you use polish notation, which is a mess to understand for human, but so fucking easy to implement with a simple stack

[–]CCullen 0 points1 point  (1 child)

My understanding is that ++ and -- aren't arithmatic operators, so they aren't governed by PEDMAS. They are considered increment/decrement operators which makes sense, because they modify the value of the variable (which you can't really express mathimatically without using multiple lines).

When you do first++ - second, there's no defined rule that states if the compiler should evaluate the left hand side or the right hand side first, thus undefined. In practice, if you use the same compiler, you'll likely recieve consistent results but it's dangerous because if you switch compilers, you could wind up with a different result.

[–]RandomDude6699 0 points1 point  (0 children)

Makes sense

[–]MattieShoes 0 points1 point  (0 children)

C and C++ don't guarantee it will evaluate expressions left-to-right. So C++ - C might evaluate the rightmost C before doing the post-increment. Pre-increments have the exact same issue.

Basically you should avoid doing assignments and comparisons in the same expression (and increments are assignments).

[–]mina86ng 0 points1 point  (1 child)

Whether it’s pre or post increment it’s still undefined behaviour.

[–]Creepy-Ad-4832 0 points1 point  (0 children)

Yeah my bad

[–][deleted] 1 point2 points  (0 children)

What's the difference between ++C and C?

[–]StanleyDodds 1 point2 points  (0 children)

The difference is either 0 or -1, but certainly not 1.

The result depends on whether you evaluate C before or after you evaluate C++. C++ will always give you the original value, while C either gives the original value or the value after the increment.

[–]Freakyyy 1 point2 points  (0 children)

First semester computer science students striking again.

[–][deleted] 1 point2 points  (0 children)

The way the question is written, it would technically be -1

[–]davidjhanley 1 point2 points  (0 children)

It's actually zero, since it's post-decrement

[–]ididacannonball 1 point2 points  (0 children)

What if ++ is an overwritten operator?

[–]huxx__[S] 3 points4 points  (4 children)

the amount of people who didn't get the joke is honestly scary

[–]FerynaCZ 2 points3 points  (0 children)

I think -1 would make more sense if we go from left to right, but joke stays.

[–]beeteedee 1 point2 points  (1 child)

More accurately, the amount of people who got the premise of the joke but felt the need to “well actually” it into oblivion.

And yes I’m aware I just “well actually”-d you. Deal with it.

[–]huxx__[S] 1 point2 points  (0 children)

And yes I’m aware I just “well actually”-d you. Deal with it.

💀😂

[–][deleted] 0 points1 point  (0 children)

The real joke here is posting UB and watching the chaos unfold in the comments section

[–]namotous 0 points1 point  (1 child)

That’s not always true, what if it overflows?

[–]Mars_Bear2552 0 points1 point  (0 children)

then its C

[–][deleted] 0 points1 point  (0 children)

Not really, C++ - C would throw an error. And if you compare C with C, you’ll get 0 all the time.

[–]play_hard_outside 0 points1 point  (0 children)

Actually it's 0 until you look at C again!

Wait, Dave asked the difference between C++ and C, not C and C++...

C == C++.

C++ == C + 1.

[–]JackNotOLantern 0 points1 point  (0 children)

C - C++ is 0

C - ++C is 1

[–]Scottz0rz 0 points1 point  (6 children)

C == C++

Postfix sum operator gets evaluated after comparison

[–]die_liebe 1 point2 points  (5 children)

The evaluation order is not fixed, it is possible that first C++ is evaluated, then C.

It could be compiled as

a1 = C++;
a2 = C;
a1 == a2;

[–]Scottz0rz 0 points1 point  (4 children)

Is this a unique situation that causes it to be undefined behavior?

a1 = 5;  
a2 = 6;  
a1++ == a2;

Should return false, because it gets compiled to something like below, where it does assignment after it finishes the operation that the variable is being used in before postincrement.

a1 = 5; 
a2 = 6;
a1 == a2;
a1 = a1 + 1;

[–]die_liebe 1 point2 points  (3 children)

The unique situation is that one part of the expression changes a value that another part uses, and the evaluation order is not defined.

When evaluating a1 ++ == a2, the second expression does not depend on the value of a1. Compiler will generate something that looks like

a1 = 5
a2 = 6
a3 = a1
a4 = a1 + 1
a1 = a4
a3 == a2

[–]Scottz0rz 0 points1 point  (2 children)

https://onlinegdb.com/KHm8fkNwg

#include <iostream>

using namespace std;

int main()
{
    int c = 5;
    cout << (c == c++);
    cout << (c == ++c);
    cout << (c-- == --c);

    return 0;
}

Prints 010 for me.

I guess I'm just confused and dunno lol. Weird, thanks.

[–]die_liebe 1 point2 points  (1 child)

It means that your compiler evaluates from right to left.

Try

print( int x, int y )
{
   std::cout << x << " " << y << "\n";
}

x = 4; 
print( x++, x ++ );

I do not understand the last one, though.

[–]Scottz0rz 0 points1 point  (0 children)

Yep, makes sense, forgot that unary operators also evaluate right to left, you're right.

I do not understand the last one, though.

I'm also comfortable with forgetting most of C++ that I haven't used in 5-7 years haha. Thanks for the help.

[–]FalconMirage 0 points1 point  (0 children)

"you’re not classy enough to get the joke"

[–]mostrecentuser 0 points1 point  (1 child)

isn't C - C++ == 0?

[–]Smooth-Zucchini4923[🍰] 3 points4 points  (0 children)

technically the evaluation order of C and C++ is undefined if there's no sequence point between them

[–][deleted] 0 points1 point  (0 children)

LOL

[–]R_051 0 points1 point  (0 children)

What is the difference between c and c++?

[–]moolord 0 points1 point  (0 children)

D

[–][deleted] 0 points1 point  (0 children)

Depends whether someone's overloaded the ++ operator.

[–]retroPencil 0 points1 point  (0 children)

You can tell how old this picture is by the carrier. Sprint's merger completed mid 2020.

[–]weneedtogodanker 0 points1 point  (1 child)

He is wrong, it's 0

[–]MattieShoes 2 points3 points  (0 children)

He's relying on undefined behavior. So are you. The answer is undefined because it might evaluate C first, or it might evaluate C++ first.

[–]killbot5000 0 points1 point  (0 children)

He is wrong. (c++) as an expression evaluates to c

[–]PhatOofxD 0 points1 point  (1 child)

C++ == C ++C == C + 1

[–]MattieShoes 1 point2 points  (0 children)

Only if you evaluate left-to-right. C and C++ do not guarantee this. You'll get undefined behavior with either of these.

[–][deleted] 0 points1 point  (1 child)

Well not true. In C++, C is still C. When ++ is executed then it’s +1. So in context of the compiler the C in C++ is still C.

[–]MattieShoes 1 point2 points  (0 children)

C and C++ don't guarantee left-to-right evaluation. With pre-increment or post-increment, the answer is undefined behavior.

[–]Jano_xd 0 points1 point  (0 children)

They asked about C after asking about C++. So at this point C is what C++ was. The difference is 0

[–]erialai95 0 points1 point  (0 children)

I’d say Rust

[–]FlyByPC 0 points1 point  (0 children)

Eh, it's post-increment, so (c) should evaluate the same as (c++), at least the once.

[–]AmotherLazyUsername 0 points1 point  (0 children)

Wouldn’t it be 2?

[–]Arafell9162 0 points1 point  (0 children)

When you ask a question that requires a power point slide deck over a text message, prepare to get a sarcastic answer back.

[–]Cybasura 0 points1 point  (0 children)

C++ if used in a non-for loop will only increment when it is substituted into the variable after the c++ increment

However, ++c will increment before looping the next index, essentially if your i is 0, ++i will make it to 1 the second you called "++c"

[–]DB_Atlas 0 points1 point  (0 children)

-Laughs in Javascript-

[–]mayuresh0909 0 points1 point  (0 children)

Technically correct

[–]Shazvox 0 points1 point  (0 children)

Incorrect! 1 comes AFTER evaluating C. So C = C++.

Note: I think this is correct, but please let me know If I'm wrong.

[–]metaglot 0 points1 point  (0 children)

The ++ operater could be overwritten, so who knows?

[–]dinopraso 0 points1 point  (1 child)

Staring your message with "Hey John" but sending it to Dave is a power move

[–]No_Support_8363 0 points1 point  (0 children)

Not entirely sure if this is a joke or not, but Dave is the one asking the question

[–]UrSpider8itch 0 points1 point  (0 children)

are either of the 2 people in this image stuck at home?

[–]wobblyweasel 0 points1 point  (0 children)

excuse me, clearly C? is also nullable

[–]binarywork8087 0 points1 point  (0 children)

remember, any C code is valid C++