Author Topic: An 'interesting' thing you can do in C++  (Read 18771 times)

0 Members and 1 Guest are viewing this topic.

Offline hamster_nzTopic starter

  • Super Contributor
  • ***
  • Posts: 2803
  • Country: nz
An 'interesting' thing you can do in C++
« on: September 11, 2018, 03:42:07 am »
Just when you think you have seen it all...

Code: [Select]
#include <stdio.h>

int main(int argc, char *argv[]) {
  int a=  0, b = 0;

  (argc == 2 ? a : b) += 5;

  printf("%i %i\n",a,b);
  return 0;
}

I guess it could be useful...

Has anybody used/found a use for this?
Gaze not into the abyss, lest you become recognized as an abyss domain expert, and they expect you keep gazing into the damn thing.
 

Offline IanB

  • Super Contributor
  • ***
  • Posts: 11885
  • Country: us
Re: An 'interesting' thing you can do in C++
« Reply #1 on: September 11, 2018, 03:53:38 am »
What am I looking at? Is there something to see here?
 

Offline hamster_nzTopic starter

  • Super Contributor
  • ***
  • Posts: 2803
  • Country: nz
Re: An 'interesting' thing you can do in C++
« Reply #2 on: September 11, 2018, 04:13:27 am »
What am I looking at? Is there something to see here?

Code: [Select]
  (argc == 2 ? a : b) += 5;

You can use the '?' operator, to select one of two different variables to be the target of the assignment.
Gaze not into the abyss, lest you become recognized as an abyss domain expert, and they expect you keep gazing into the damn thing.
 

Offline ejeffrey

  • Super Contributor
  • ***
  • Posts: 3719
  • Country: us
Re: An 'interesting' thing you can do in C++
« Reply #3 on: September 11, 2018, 04:51:42 am »
The point is I guess that the result of ?: can be an lvalue assuming arguments 2 and 3 are.

This is only allowed in C++, not C.  I'm not sure what motivation, if any, lead to the change.
 

Offline hamster_nzTopic starter

  • Super Contributor
  • ***
  • Posts: 2803
  • Country: nz
Re: An 'interesting' thing you can do in C++
« Reply #4 on: September 11, 2018, 05:24:47 am »
The point is I guess that the result of ?: can be an lvalue assuming arguments 2 and 3 are.

This is only allowed in C++, not C.  I'm not sure what motivation, if any, lead to the change.

My guess of the motivation is : "It's not feature complete, until it is Turing Complete"
Gaze not into the abyss, lest you become recognized as an abyss domain expert, and they expect you keep gazing into the damn thing.
 

Offline boffin

  • Supporter
  • ****
  • Posts: 1027
  • Country: ca
Re: An 'interesting' thing you can do in C++
« Reply #5 on: September 11, 2018, 05:39:45 am »
And it's single lines of code like that, that make it damn near impossible to debug.  When you go back two years later, it's not obvious what is happening
 
The following users thanked this post: BillyD, kony, Tom45, nugglix, TomS_

Offline westfw

  • Super Contributor
  • ***
  • Posts: 4199
  • Country: us
Re: An 'interesting' thing you can do in C++
« Reply #6 on: September 11, 2018, 05:40:44 am »
I find the "creeping featurism" of C++ to be ... alarming.
Already, the Open Source programs you can find look nothing like the basic C++ that one learns in school, and frequently they don't look much like each other, either.   And they keep going "no wait!   There's a weird punctuation character we haven't used yet, George at U of X wants it, and it allows programmers to avoid doing an  obscure thing bt doing this MORE OBSCURE thing instead!"
No wonder so many people stick with C.
 
The following users thanked this post: BillyD

Offline Berni

  • Super Contributor
  • ***
  • Posts: 4954
  • Country: si
Re: An 'interesting' thing you can do in C++
« Reply #7 on: September 11, 2018, 05:45:36 am »
Oh wow, had no idea you could do that.

But how useful it is? Im not so sure. It does condense down what would otherwise be an IF statement down into just one line, but its also kinda hard to read. Higher level compilers are made for the purpose of making code easier to read so i guess this is a bad feature to add.

Then again its probably getting hard to come up with new features ideas for C since all the great features have already been put in there (Features that are in the spirit of C being close to the hardware that is)
 

Offline TomS_

  • Frequent Contributor
  • **
  • Posts: 834
  • Country: gb
Re: An 'interesting' thing you can do in C++
« Reply #8 on: September 11, 2018, 06:14:06 am »
And it's single lines of code like that, that make it damn near impossible to debug.  When you go back two years later, it's not obvious what is happening

This ^^

Have a read of the MISRA C spec. Sometimes I joke that it should be called MISRAble because its quite restrictive sometimes, but having been bitten by some of the very things it tries to protect against in my own personal projects, Ive taken some of it on board.

e.g. I used to think it was nifty not having to wrap single statements following if or loop statements in braces, but then a couple of times while not really thinking about it I added some extra statements and forgot to add the braces and wondered why it wasnt working, only to spend a while debugging and then realising they werent part of the same block of code. So now I avoid that kind of syntax and use braces even for single statements. I could probably partially blame the fact I write a lot of python for that too (because they were indented to the same level). :-DD

When you work as a professional programmer in any kind of capacity, you come to appreciate that readability trumps all, especially when you may have to re-read code months or even years down the line, or you have to read someone elses code, or someone else has to read your code.
 
The following users thanked this post: JPortici

Offline maginnovision

  • Super Contributor
  • ***
  • Posts: 1963
  • Country: us
Re: An 'interesting' thing you can do in C++
« Reply #9 on: September 11, 2018, 06:34:56 am »
That's just for consistency. Some of the guys in charge value consistency over... everything else. So this is an example of that. I probably wouldn't use something like that except for a lambda. Even then rarely.
 

Offline SparkyFX

  • Frequent Contributor
  • **
  • Posts: 676
  • Country: de
Re: An 'interesting' thing you can do in C++
« Reply #10 on: September 11, 2018, 08:04:46 am »
Code: [Select]
  (argc == 2 ? a : b) += 5;

You can use the '?' operator, to select one of two different variables to be the target of the assignment.
I like the question mark operator with colon as a short for an "if" "then" "else" construct replacement, it really speeds up things and makes the code fast to write, and even does enable new ways to write code like the example shown.

And it's single lines of code like that, that make it damn near impossible to debug.  When you go back two years later, it's not obvious what is happening
Relatively understandable for anyone with some Perl knowledge ... not exactly but close.

« Last Edit: September 11, 2018, 08:10:18 am by SparkyFX »
Support your local planet.
 

Offline nfmax

  • Super Contributor
  • ***
  • Posts: 1560
  • Country: gb
Re: An 'interesting' thing you can do in C++
« Reply #11 on: September 11, 2018, 08:18:19 am »
So, what do you think would be the values of a and b after the following code runs (assuming all three variables are declared as int)?
Code: [Select]
a = 0;
b = 0;
ptr = 17;
(++ptr == 18 ? a : b ) = ptr--;
 

Offline hamster_nzTopic starter

  • Super Contributor
  • ***
  • Posts: 2803
  • Country: nz
Re: An 'interesting' thing you can do in C++
« Reply #12 on: September 11, 2018, 08:50:41 am »
So, what do you think would be the values of a and b after the following code runs (assuming all three variables are declared as int)?
Code: [Select]
a = 0;
b = 0;
ptr = 17;
(++ptr == 18 ? a : b ) = ptr--;
Not sure. Would need to test.

Hunch would be that it is evaluated left to right, so a will be 18, b will be zero.

But this is more a problem of the ambiguity of using ++ and -- at the same time as acessing the value of a variable.

foo(++a, ++a, a--) is much the same.

If it was written:

(ptr+1 == 18 ? a : b ) = ptr+1;

or

ptr++;
(ptr == 18 ? a : b ) = ptr;
ptr--;

Then there is no problem.

Gaze not into the abyss, lest you become recognized as an abyss domain expert, and they expect you keep gazing into the damn thing.
 

Offline SparkyFX

  • Frequent Contributor
  • **
  • Posts: 676
  • Country: de
Re: An 'interesting' thing you can do in C++
« Reply #13 on: September 11, 2018, 09:10:56 am »
rewrite to
if (++ptr == 18) { a = ptr-- } else { b = ptr-- };
And you are not any smarter.

It is not as if this stops someone from doing ambigous stuff, just because it is a different way of writing if ... else.

At least i hope i got the topic correct and it is about this operator, not about returning variables for lvalue assignment, which is interesting in itself.
« Last Edit: September 11, 2018, 09:16:04 am by SparkyFX »
Support your local planet.
 

Offline brucehoult

  • Super Contributor
  • ***
  • Posts: 4036
  • Country: nz
Re: An 'interesting' thing you can do in C++
« Reply #14 on: September 11, 2018, 09:23:14 am »
And it's single lines of code like that, that make it damn near impossible to debug.  When you go back two years later, it's not obvious what is happening

Why? What's difficult about it?

You've always been able to do the same thing as...

Code: [Select]
*(argc == 2 ? &a : &b) += 5;
 
The following users thanked this post: amyk, newbrain

Offline nfmax

  • Super Contributor
  • ***
  • Posts: 1560
  • Country: gb
Re: An 'interesting' thing you can do in C++
« Reply #15 on: September 11, 2018, 10:03:50 am »
The difficulty arises because it is unclear which of the ptr-modifying expressions is evaluated first - the one in the rvalue or the one in the xvalue. The preincrement/postdecrement complication is just a red herring, intended to distract!

Code should be written to be easy to read and understand!
 
The following users thanked this post: TomS_

Offline taydin

  • Frequent Contributor
  • **
  • Posts: 520
  • Country: tr
Re: An 'interesting' thing you can do in C++
« Reply #16 on: September 11, 2018, 10:56:17 am »
e.g. I used to think it was nifty not having to wrap single statements following if or loop statements in braces, but then a couple of times while not really thinking about it I added some extra statements and forgot to add the braces and wondered why it wasnt working, only to spend a while debugging and then realising they werent part of the same block of code. So now I avoid that kind of syntax and use braces even for single statements.

I can second this recommendation. Putting in braces even when not necessary helps clearly see the "if" actions and "else" actions and it really helps somebody else (or you, after you haven't looked at it for a while) maintain your code.

Young programmers that are just starting out will often use clever, exotic features of the language in their code, in an attempt to prove that they are intelligent and proficient. But they just end up proving the opposite  :(
Real programmers use machine code!

My hobby projects http://mekatronik.org/forum
 
The following users thanked this post: CustomEngineerer, TomS_

Offline cgroen

  • Supporter
  • ****
  • Posts: 631
  • Country: dk
    • Carstens personal web
Re: An 'interesting' thing you can do in C++
« Reply #17 on: September 11, 2018, 01:06:21 pm »
e.g. I used to think it was nifty not having to wrap single statements following if or loop statements in braces, but then a couple of times while not really thinking about it I added some extra statements and forgot to add the braces and wondered why it wasnt working, only to spend a while debugging and then realising they werent part of the same block of code. So now I avoid that kind of syntax and use braces even for single statements.

I can second this recommendation. Putting in braces even when not necessary helps clearly see the "if" actions and "else" actions and it really helps somebody else (or you, after you haven't looked at it for a while) maintain your code.

Young programmers that are just starting out will often use clever, exotic features of the language in their code, in an attempt to prove that they are intelligent and proficient. But they just end up proving the opposite  :(

And old programmers will often stick with the old ways and totally ignore the new and better features as they are stuck in "good old times" ;)
PS: I have been a professional developer for 34+ years, so this probably also goes for me in some way  ;)
 
The following users thanked this post: hans

Offline nfmax

  • Super Contributor
  • ***
  • Posts: 1560
  • Country: gb
Re: An 'interesting' thing you can do in C++
« Reply #18 on: September 11, 2018, 01:29:02 pm »
You can pull the same sort of stunt in plain old C:
Code: [Select]
#include <stdio.h>

int main(int argc, char** argv) {
int array[] = {0,1,2};
int index = 0;

printf("Before: array = [%d, %d, %d], index = %d\n", array[0], array[1], array[2], index);
array[index++] = index++;

printf("After: array = [%d, %d, %d], index = %d\n", array[0], array[1], array[2], index);
return 0;
}

Which compiles (with a warning) and runs to give:
Code: [Select]
Before: array = [0, 1, 2], index = 0
After: array = [0, 0, 2], index = 2

So the rvalue is expression is evaluated first. However, the warning message is revealing:
Code: [Select]
wotsit.c:8:13: warning: multiple unsequenced modifications to 'index' [-Wunsequenced]
        array[index++] = index++;
                   ^          ~~
1 warning generated.

as it implies this behaviour is not guaranteed.

Don't Do Things Like This!
« Last Edit: September 11, 2018, 01:33:41 pm by nfmax »
 

Offline GeorgeOfTheJungle

  • Super Contributor
  • ***
  • !
  • Posts: 2699
  • Country: tr
Re: An 'interesting' thing you can do in C++
« Reply #19 on: September 11, 2018, 01:53:43 pm »
The point is I guess that the result of ?: can be an lvalue assuming arguments 2 and 3 are.

This is only allowed in C++, not C.  I'm not sure what motivation, if any, lead to the change.

It compiles ~ fine in gcc 4.2/2007

Code: [Select]
#include <stdio.h>

int main (int argc, char *argv[]) {
    int a=  0, b = 0;
    (argc == 2 ? a : b) += 5;
    printf("%i %i\n",a,b);
    return 0;
}

jorge@unibody:~/kk$ gcc --version
i686-apple-darwin10-llvm-gcc-4.2 (GCC) 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.6)
Copyright (C) 2007 Free Software Foundation, Inc.

jorge@unibody:~/kk$ gcc kk.c -o kk.out
kk.c: In function ‘main’:
kk.c:5: warning: target of assignment not really an lvalue; this will be a hard error in the future
jorge@unibody:~/kk$ ./kk.out
0 5
jorge@unibody:~/kk$ ./kk.out 1
5 0
jorge@unibody:~/kk$
« Last Edit: September 11, 2018, 02:04:05 pm by GeorgeOfTheJungle »
The further a society drifts from truth, the more it will hate those who speak it.
 

Offline grumpydoc

  • Super Contributor
  • ***
  • Posts: 2905
  • Country: gb
Re: An 'interesting' thing you can do in C++
« Reply #20 on: September 11, 2018, 01:57:30 pm »
This is only allowed in C++, not C.  I'm not sure what motivation, if any, lead to the change.

No but in C one can write *(argc == 2 ? &a : &b) += 5;

If you really want

Yes I have done this, but I'm not proud of it (outside of intentionally obfuscated code).
 

Offline GeorgeOfTheJungle

  • Super Contributor
  • ***
  • !
  • Posts: 2699
  • Country: tr
Re: An 'interesting' thing you can do in C++
« Reply #21 on: September 11, 2018, 02:03:03 pm »
Young programmers often ignore the reason why things are the way they are... and tend to use tabs instead of spaces  >:D and put blocks in ifs and loops when there's no need  >:D because a comma operator would do  >:D but they just don't know it  >:D

Code: [Select]
while (young) make(), mistakes();
The further a society drifts from truth, the more it will hate those who speak it.
 

Offline rstofer

  • Super Contributor
  • ***
  • Posts: 9890
  • Country: us
Re: An 'interesting' thing you can do in C++
« Reply #22 on: September 11, 2018, 02:08:48 pm »
I must be getting old!  Not only do I not know what some of these constructs will do, I don't even want to know.  I would never write something like that!  I really don't like 'clever' code.

I'm of the opinion that I should write code as clearly as possible and let the compiler worry about optimization.

 
The following users thanked this post: TheWelly888, nctnico, nfmax, JPortici, Mr. Scram

Offline GeorgeOfTheJungle

  • Super Contributor
  • ***
  • !
  • Posts: 2699
  • Country: tr
Re: An 'interesting' thing you can do in C++
« Reply #23 on: September 11, 2018, 02:25:58 pm »
No but in C one can write *(argc == 2 ? &a : &b) += 5;

Yep. That's clear and unambiguous and compiles without warnings. C++ is obscure, a mine field. Sometimes I wonder if Stroustrup eats mushrooms.
The further a society drifts from truth, the more it will hate those who speak it.
 

Offline dferyance

  • Regular Contributor
  • *
  • Posts: 181
Re: An 'interesting' thing you can do in C++
« Reply #24 on: September 11, 2018, 02:29:18 pm »
In my experience young programmers don't make mistakes. They pip or npm install 1000 random packages in python or node hoping that some of them will do what they need. Glue together other people's work; writing code is so retro!

On a more serious note, I get some of the frustration with the complexities of C++. Despite plenty of the downsides, i've learned to really respect C and C++ for not getting in your way. So many other programming languages and libraries want to "encourage" / force you to code a certain way. This kind of "opinionated software" is considered good. There are vastly different needs between engineering projects. While C++ doesn't help you much or hold your hand, at least it doesn't try to force all your projects to be written like a REST api, or document editor or whatever the language designer likes to code.
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3146
  • Country: ca
Re: An 'interesting' thing you can do in C++
« Reply #25 on: September 11, 2018, 02:45:47 pm »
Code: [Select]
while (young) make(), mistakes();

Code: [Select]
while (make(), mistakes(), !dead);

 
The following users thanked this post: hans, GeorgeOfTheJungle, newbrain

Offline nctnico

  • Super Contributor
  • ***
  • Posts: 26906
  • Country: nl
    • NCT Developments
Re: An 'interesting' thing you can do in C++
« Reply #26 on: September 11, 2018, 02:48:03 pm »
And it's single lines of code like that, that make it damn near impossible to debug.  When you go back two years later, it's not obvious what is happening
I fully agree. Using these kind of constructs should be banned.
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 
The following users thanked this post: TomS_

Offline HoracioDos

  • Frequent Contributor
  • **
  • Posts: 344
  • Country: ar
  • Just an IT monkey with a DSO
Re: An 'interesting' thing you can do in C++
« Reply #27 on: September 11, 2018, 02:53:06 pm »
Yep. That's clear and unambiguous and compiles without warnings. C++ is obscure, a mine field. Sometimes I wonder if Stroustrup eats mushrooms.
I'm not a C++ programmer but one of his quotes would give me goosebumps. "C makes it easy to shoot yourself in the foot; C++ makes it harder, but when you do it blows your whole leg off"
 
The following users thanked this post: GeorgeOfTheJungle

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3146
  • Country: ca
Re: An 'interesting' thing you can do in C++
« Reply #28 on: September 11, 2018, 03:02:08 pm »
I fully agree. Using these kind of constructs should be banned.

By whom?
 

Offline dferyance

  • Regular Contributor
  • *
  • Posts: 181
Re: An 'interesting' thing you can do in C++
« Reply #29 on: September 11, 2018, 04:08:53 pm »
Whenever I've seen people attempt to ban language features, it never really worked well. Some features make sense in certain cases but don't in others. What constructs one developer thinks are horrible, often another developer finds straightforward.

I've known programmers who like massive if/else chains to assign variable values. While I prefer simple variable assignment, sometimes with a ternary operator. I find the latter much simpler to reason about and understand as it is a formula instead of a large logic chain. But other developers like to think of it in terms of conditional statements and logic chains. Who's right here? Really there isn't a right or wrong.

Its not possible to dictate good code through some codified rules. Good programming takes a lifetime to master. It would be nice if all it took was a few rules. There are very few if any language constructs I would say never to use. Unless something else fully replaces it, they often have their purpose. But it is important to use them as clearly as possible. All language constructs can be abused.
 

Offline taydin

  • Frequent Contributor
  • **
  • Posts: 520
  • Country: tr
Re: An 'interesting' thing you can do in C++
« Reply #30 on: September 11, 2018, 04:22:33 pm »
Compared to other languages, C/C++ has very few rules. Successful programmers adopt a set of "best practices" and follow those. The MISRA recommendations, and Scott Meyers "effective C++" recommendations are good starting points for establishing ones own best practices.

If one uses all the freedom that C/C++ gives, the result will be a unmaintainable mess, a money pit.
Real programmers use machine code!

My hobby projects http://mekatronik.org/forum
 

Offline rstofer

  • Super Contributor
  • ***
  • Posts: 9890
  • Country: us
Re: An 'interesting' thing you can do in C++
« Reply #31 on: September 11, 2018, 04:41:22 pm »
Mentioned above and bearing repeating, it remains an exercise to determine which C compilers produce predictable output for some of these more obscure constructs.  What happens when the latest and greatest kicks some of these constructs to the curb?

I know what ++var and var++ do when they are either on the right or left side of the '=' sign.  I wouldn't want to predict what would happen if they are on both sides.  I know what I think they should do but I wouldn't want to bet that any particular compiler will do what I think.  Moreover, I wouldn't want to predict that they will ALL do what I think.

I started reading the MISRA standard and perhaps I'll look into "Effective C++" but, basically, I stay completely away from C++.
 

Offline taydin

  • Frequent Contributor
  • **
  • Posts: 520
  • Country: tr
Re: An 'interesting' thing you can do in C++
« Reply #32 on: September 11, 2018, 04:53:58 pm »
I use C++ often, but only to get the following advantages compared to C: Better type safety, templates, exceptions. Haven't used C++ OOP that much.
Real programmers use machine code!

My hobby projects http://mekatronik.org/forum
 

Offline glarsson

  • Frequent Contributor
  • **
  • Posts: 814
  • Country: se
Re: An 'interesting' thing you can do in C++
« Reply #33 on: September 11, 2018, 05:00:08 pm »
Don't try to predict undefined behavior. It is undefined!

f(a++,a++); is undefined.
a=a++; is undefined.

It doesn't matter if the ++ is on the left or right side of = or the number of ++. What matters is the number of times a variable is modified between sequence points. More than one means undefined behavior.
 
The following users thanked this post: newbrain

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3146
  • Country: ca
Re: An 'interesting' thing you can do in C++
« Reply #34 on: September 11, 2018, 05:14:59 pm »
I know what ++var and var++ do when they are either on the right or left side of the '=' sign.  I wouldn't want to predict what would happen if they are on both sides.  I know what I think they should do but I wouldn't want to bet that any particular compiler will do what I think.  Moreover, I wouldn't want to predict that they will ALL do what I think.

In C, the order is not specified - the evaluation may happen in any order. So, the code like this:

Code: [Select]
x[a++] = a++;
may be executed as either

Code: [Select]
temp1 = a;
a++;
temp2 = a;
a++;
x[temp1] = temp2;

or

Code: [Select]
temp2 = a;
a++;
temp1 = a;
a++;
x[temp1] = temp2;

or even

Code: [Select]
temp1 = a;
temp2 = a;
a++;
a++;
x[temp1] = temp2;

 

Offline glarsson

  • Frequent Contributor
  • **
  • Posts: 814
  • Country: se
Re: An 'interesting' thing you can do in C++
« Reply #35 on: September 11, 2018, 05:34:07 pm »
Or even a[0]=42;.
 
The following users thanked this post: newbrain

Offline GeorgeOfTheJungle

  • Super Contributor
  • ***
  • !
  • Posts: 2699
  • Country: tr
Re: An 'interesting' thing you can do in C++
« Reply #36 on: September 11, 2018, 05:46:35 pm »
The further a society drifts from truth, the more it will hate those who speak it.
 

Online MK14

  • Super Contributor
  • ***
  • Posts: 4539
  • Country: gb
Re: An 'interesting' thing you can do in C++
« Reply #37 on: September 11, 2018, 05:58:42 pm »
Or even a[0]= 42;.
Watt?

What I think he means, is that since it is UNDEFINED, anything can happen.
 
The following users thanked this post: GeorgeOfTheJungle, newbrain

Offline grumpydoc

  • Super Contributor
  • ***
  • Posts: 2905
  • Country: gb
Re: An 'interesting' thing you can do in C++
« Reply #38 on: September 11, 2018, 05:59:32 pm »
Or even a[0]= 42;.
Watt?
"undefined" means just that, any result is within the guarantees set by the language, including turning your mother green and causing your computer to explode (OK not, terribly likely but within the permitted behaviour).

 ;)  >:D

Or even a[0]= 42;.
Watt?

What I think he means, is that since it is UNDEFINED, anything can happen.
Yup.
 
The following users thanked this post: GeorgeOfTheJungle, MK14

Offline ajb

  • Super Contributor
  • ***
  • Posts: 2603
  • Country: us
Re: An 'interesting' thing you can do in C++
« Reply #39 on: September 11, 2018, 06:06:53 pm »
Or even a[0]= 42;.
Watt?
"undefined" means just that, any result is within the guarantees set by the language, including turning your mother green and causing your computer to explode (OK not, terribly likely but within the permitted behaviour).

 ;)  >:D

While anything *could* happen, a sensible implementation should give you the expected behavior.
« Last Edit: September 11, 2018, 06:08:24 pm by ajb »
 

Offline glarsson

  • Frequent Contributor
  • **
  • Posts: 814
  • Country: se
Re: An 'interesting' thing you can do in C++
« Reply #40 on: September 11, 2018, 06:18:45 pm »
What is the expected behavior? What is sensible from the point of the compiler will vary depending on compiler, CPU type, optimization level, the source code surrounding the undefined code,..., and the programmer having the expectation.

Please don't argue that undefined behavior do have a defined behavior.
 
The following users thanked this post: hans, ralphrmartin, newbrain, MK14

Offline ajb

  • Super Contributor
  • ***
  • Posts: 2603
  • Country: us
Re: An 'interesting' thing you can do in C++
« Reply #41 on: September 11, 2018, 06:42:00 pm »
What is the expected behavior?
That's explained in the link...
 

Offline grumpydoc

  • Super Contributor
  • ***
  • Posts: 2905
  • Country: gb
Re: An 'interesting' thing you can do in C++
« Reply #42 on: September 11, 2018, 06:52:48 pm »
What is the expected behavior?
That's explained in the link...
See, I think turning your mother green is much better than having daemons fly out of your nose.

Although, possibly, they could then turn your mother green as a parting shot. >:D

 
The following users thanked this post: newbrain

Offline glarsson

  • Frequent Contributor
  • **
  • Posts: 814
  • Country: se
Re: An 'interesting' thing you can do in C++
« Reply #43 on: September 11, 2018, 07:04:46 pm »
That's explained in the link...
No. That discussion is about using sizeof() on an undefined struct. This must be diagnosed by the compiler (error message) and will therefore not have the opportunity to invoke undefined behavior at runtime. So no formatted disks.
 
The following users thanked this post: newbrain

Offline ajb

  • Super Contributor
  • ***
  • Posts: 2603
  • Country: us
Re: An 'interesting' thing you can do in C++
« Reply #44 on: September 11, 2018, 07:09:55 pm »
Perhaps this link will clear things up.
 

Online MK14

  • Super Contributor
  • ***
  • Posts: 4539
  • Country: gb
Re: An 'interesting' thing you can do in C++
« Reply #45 on: September 11, 2018, 07:16:19 pm »
Perhaps this link will clear things up.

Sorry!, It hasn't.
My nose is blocked, I'm coughing, the lights have dimmed, strange things are buzzing round and a picture of my mother has just turned green.
 

Offline glarsson

  • Frequent Contributor
  • **
  • Posts: 814
  • Country: se
Re: An 'interesting' thing you can do in C++
« Reply #46 on: September 11, 2018, 07:21:19 pm »
Perhaps you shouldn't run your code on the DeathStation 9000.

http://wikibin.org/articles/deathstation-9000.html
 
The following users thanked this post: MK14

Online MK14

  • Super Contributor
  • ***
  • Posts: 4539
  • Country: gb
Re: An 'interesting' thing you can do in C++
« Reply #47 on: September 11, 2018, 07:29:45 pm »
Perhaps you shouldn't run your code on the DeathStation 9000.

http://wikibin.org/articles/deathstation-9000.html

That's brilliant!
 

Offline nctnico

  • Super Contributor
  • ***
  • Posts: 26906
  • Country: nl
    • NCT Developments
Re: An 'interesting' thing you can do in C++
« Reply #48 on: September 11, 2018, 08:13:21 pm »
I fully agree. Using these kind of constructs should be banned.
By whom?
By sane people ofcourse  >:D
Unless you want to get stuck maintaining the same code forever you better write your code in a way a complete novice can understand it and not screw it up when making changes.
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 
The following users thanked this post: TomS_, Mr. Scram

Offline ogden

  • Super Contributor
  • ***
  • Posts: 3731
  • Country: lv
Re: An 'interesting' thing you can do in C++
« Reply #49 on: September 11, 2018, 08:45:38 pm »
I fully agree. Using these kind of constructs should be banned.
By whom?
By sane people ofcourse  >:D

Indeed. There's very good advise in Linux kernel coding style document"don’t break the internal parsers of those who will read the code"
 
The following users thanked this post: Ian.M, Mr. Scram

Online hans

  • Super Contributor
  • ***
  • Posts: 1639
  • Country: nl
Re: An 'interesting' thing you can do in C++
« Reply #50 on: September 11, 2018, 09:07:45 pm »
This is only allowed in C++, not C.  I'm not sure what motivation, if any, lead to the change.

No but in C one can write *(argc == 2 ? &a : &b) += 5;

If you really want

Yes I have done this, but I'm not proud of it (outside of intentionally obfuscated code).

To be honest the only objection I would have is the "inline" if statement for resolving the pointer. I don't really have a problem with having somewhat "complex" code on the left hand side of an assignment expression, for example I think this kind of code is quite common:

Code: [Select]
int& getRef(int x, int y ) {
    return buffer[x*1024 + y];
}
int* getPtr(int x, int y ) {
    return &(buffer[x*1024 + y]);
}

int main(int argc, char** args) {
    *getPtr(2, 5) = 10;
    getRef(3, 5) = 10;
}

I think far worse if you start to mix variable assignment statements with control statements. For example, this is a reconstruction of a code statement I had to work with last year (you could label the source of this project as "PhD-ware"):

Code: [Select]
static auto create(...) {
  if ((source=new (hw_src_addr) obj<T, ro>[size])) == NULL) {
    PRINT_DEBUG("failed!");
    return std::make_pair(nullptr, nullptr);
  } else if (hw_src_addr!=hw_dst_addr&&(destination=new (hw_dst_addr) obj<T, wo>[size]) == NULL)) {
    delete source;
    PRINT_DEBUG("failed again!");
    return std::make_pair(nullptr, nullptr);
  } else {
    return std::make_pair(source, destination);
  }
}
|O

Although it was a C++ project because of the templates, AFAIK this is also perfectly valid C to write. Who writes variable assignments in if statements?  :-//
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3146
  • Country: ca
Re: An 'interesting' thing you can do in C++
« Reply #51 on: September 11, 2018, 09:08:45 pm »
I fully agree. Using these kind of constructs should be banned.
By whom?
By sane people ofcourse  >:D

That is essentially what is happening now. Everyone thinks he's sane and thus he follows his own rules, which may not be the same as yours, or even doesn't follow any rules at all.

Otherwise, we would need a central authority who designates some people as sane, while the rest is treated as insane. You wouldn't want that, would you?

Unless you want to get stuck maintaining the same code forever you better write your code in a way a complete novice can understand it and not screw it up when making changes.

The complete novice should have some level of competence, right? Which means that if he understands the task, he should be able to follow the code. If a ternary operator scares him, may be it wasn't a good idea to hire him in the first place. It is like an electronic engineer not being able to recognize a capacitor.
 
The following users thanked this post: hans, Siwastaja

Offline GeorgeOfTheJungle

  • Super Contributor
  • ***
  • !
  • Posts: 2699
  • Country: tr
Re: An 'interesting' thing you can do in C++
« Reply #52 on: September 11, 2018, 09:36:51 pm »
Who writes variable assignments in if statements?  :-//

I like that, I used to do it very often, now I've changed my mind and don't like to do it anymore. Some compilers (or was it linters ?) don't complain/warn if you enclose the assignment in extra parenthesis, like this:

Code: [Select]
if ((b= c+i)) something();
« Last Edit: September 12, 2018, 08:44:21 pm by GeorgeOfTheJungle »
The further a society drifts from truth, the more it will hate those who speak it.
 

Offline nctnico

  • Super Contributor
  • ***
  • Posts: 26906
  • Country: nl
    • NCT Developments
Re: An 'interesting' thing you can do in C++
« Reply #53 on: September 11, 2018, 10:13:16 pm »
Unless you want to get stuck maintaining the same code forever you better write your code in a way a complete novice can understand it and not screw it up when making changes.
The complete novice should have some level of competence, right? Which means that if he understands the task, he should be able to follow the code. If a ternary operator scares him, may be it wasn't a good idea to hire him in the first place. It is like an electronic engineer not being able to recognize a capacitor.
Capacitors come in many shapes and sizes and some are not very common. Just like obfustigated code constructs.
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 
The following users thanked this post: hamster_nz

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3146
  • Country: ca
Re: An 'interesting' thing you can do in C++
« Reply #54 on: September 11, 2018, 10:14:59 pm »
Who writes variable assignments in if statements?  :-//

I like that, I used to do it very often, now I've changed my mind and don't like do it anymore. Some compilers (or was it linters ?) don't complain/warn if you enclose the assignment in extra parenthesis, like this:

Code: [Select]
if ((b= c+i)) something();

It is not very useful in ifs, because you can always re-write:

Code: [Select]
b = c+i;
if (b) something();

or using old style:

Code: [Select]
(b = c+i)&&something();
but it is more useful in whiles:

Code: [Select]
while (b = some_complex_expression) something(b);
where the re-write looks uglier:

Code: [Select]
while (1) {
  b = some_complex_expression;
  if (!b) break;
  something(b);
}


 
The following users thanked this post: GeorgeOfTheJungle

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3146
  • Country: ca
Re: An 'interesting' thing you can do in C++
« Reply #55 on: September 11, 2018, 10:21:04 pm »
Unless you want to get stuck maintaining the same code forever you better write your code in a way a complete novice can understand it and not screw it up when making changes.
The complete novice should have some level of competence, right? Which means that if he understands the task, he should be able to follow the code. If a ternary operator scares him, may be it wasn't a good idea to hire him in the first place. It is like an electronic engineer not being able to recognize a capacitor.
Capacitors come in many shapes and sizes and some are not very common. Just like obfustigated code constructs.

Are you suggesting banning capacitors which are not very common?
 

Offline SparkyFX

  • Frequent Contributor
  • **
  • Posts: 676
  • Country: de
Re: An 'interesting' thing you can do in C++
« Reply #56 on: September 11, 2018, 11:01:04 pm »
Indeed. There's very good advise in Linux kernel coding style document"don’t break the internal parsers of those who will read the code"
Every time something is tried to be defined to the lowest common denominator or an average, someone comes around the corner, yells he does not understand it, therefore does not like it and therefore lowers that level even further. Which is where comments near the code or unit tests might come handy as an avoidance strategy.

So at some point that bar needs to get raised, not lowered.
« Last Edit: September 11, 2018, 11:04:14 pm by SparkyFX »
Support your local planet.
 
The following users thanked this post: amyk

Online SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14472
  • Country: fr
Re: An 'interesting' thing you can do in C++
« Reply #57 on: September 11, 2018, 11:09:46 pm »
I find the "creeping featurism" of C++ to be ... alarming.

Definitely. And it hurts readability in an awful lot of cases. Saving a couple lines of code in exchange for one line that almost looks like an obfuscated C contest win? I don't think so. :palm:
Besides, there are more readable ways of doing the same with pointers, as some have shown.

C++ has become such a monster that I highly doubt anyone actually knows and understands all of it. Many people tend to use their own subset of features, which makes C++ a very "fragmented" language in practice.

 

Offline Mr. Scram

  • Super Contributor
  • ***
  • Posts: 9810
  • Country: 00
  • Display aficionado
Re: An 'interesting' thing you can do in C++
« Reply #58 on: September 11, 2018, 11:32:10 pm »
I loathe fanciful notations in code. Too many code monkeys like to stroke their own egos by writing shorthand or unusual bits of code. Code that isn't as legible as it could be by using the most common expression suitable only serves to increase its dependency on documentation which we know is rarely fully up to date. It also decreases the pool of people who know what they're looking at and increases the chances of mistakes being made. Simple code is easy to maintain and that's good for everyone.

There are cases where performance van be gained by going the fancy route, but that's generally just a sign of compilers not being up to snuff. Compared to other areas software can be very ego driven. You're not a genius because you contrive things.
 

Offline ogden

  • Super Contributor
  • ***
  • Posts: 3731
  • Country: lv
Re: An 'interesting' thing you can do in C++
« Reply #59 on: September 12, 2018, 12:12:07 am »
Indeed. There's very good advise in Linux kernel coding style document"don’t break the internal parsers of those who will read the code"
Every time something is tried to be defined to the lowest common denominator or an average, someone comes around the corner, yells he does not understand it, therefore does not like it and therefore lowers that level even further.

It's not about "does not understand", but how much effort is needed to comprehend particular piece of code. You can test your skills (without yelling!) here: https://www.ioccc.org/years.html.
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3146
  • Country: ca
Re: An 'interesting' thing you can do in C++
« Reply #60 on: September 12, 2018, 01:16:51 am »
It's not about "does not understand", but how much effort is needed to comprehend particular piece of code.

You don't really need to do investigative work on the code.

When you design something, you don't design the code, you design data structures, algorithms, protocols etc. Then, once the design is done, you implement it. You can implement it in C, in other language (if you have a compiler), in assembler, whatever you see fit. Except trivial cases, the design is worth more than the implementation. If the design is worthless, the code is worthless too.

The next person who's going to work on the code needs to understand the design. The design may be immediately obvious from the code, but it may not, in which case you need comments, documents etc. Once you understand the design, you can work with the code rather easily. But before you understand the design, you have zero chance of understanding the code.

If you "inherited" code with unknown design, you can, of course, decipher the code and figure out the design. However, this is a lot of work. And after all this work you may find out that the design was mediocre and wasn't worth the investigative efforts. Often, it is much easier to abandon the code right away, re-design and re-write. But, the company which owns the code regards the code itself as an asset which they paid for and cannot abandon it for nothing. Thus, the company will not want to re-design and re-write, hence hours and hours of tedious work figuring out the code, trying to do some changes, often with unpredictable side effects. Such frankensteiny approach makes code more complicated, and often worse than the original. The code also gets more expensive, because all the countless hours spent on the unruly code are counted in. The company will value such code even more and will have even less desire to re-design and re-write, so the horrors go through years, through newly hired programmers, with no chance to stop. Meanwhile, parted from the original design, the code gets worse and worse, and working with it gets harder and harder.

Does it really have anything to do with specific constructs used in the code? I don't think so.

 
The following users thanked this post: hans, Siwastaja, SparkyFX

Offline amyk

  • Super Contributor
  • ***
  • Posts: 8275
Re: An 'interesting' thing you can do in C++
« Reply #61 on: September 12, 2018, 01:56:13 am »
For what it's worth, I'm a long-time C programmer and had no trouble at all understanding what the code in OP did. The ternary lvalue is a GCC extension for C, I believe.

I don't get all the squeamishness (for lack of better term) about the ternary operator. It literally looks like you're asking a question and choosing one of two alternatives. Not hard at all.

Templated classes and nested templates, on the other hand... :scared:
 

Offline bson

  • Supporter
  • ****
  • Posts: 2270
  • Country: us
Re: An 'interesting' thing you can do in C++
« Reply #62 on: September 12, 2018, 03:06:44 am »
This is only allowed in C++, not C.  I'm not sure what motivation, if any, lead to the change.
Probably so you can easily do templates that have lvalues as type parameters.

Code: [Select]
// Function that returns the max
template <typename T>
T max(T a, T b) {
   return a > b ? a : b;
}

// Function that returns the min
template <typename T>
T min(T a, T b) {
   return a <= b ? a : b;
}

uint32_t num_nodes;
uint32_t num_values;

void clamp() {
    max<uint32_t&>(num_nodes, num_values) = min(num_nodes, num_values);
}

 

Offline bsfeechannel

  • Super Contributor
  • ***
  • Posts: 1667
  • Country: 00
Re: An 'interesting' thing you can do in C++
« Reply #63 on: September 12, 2018, 05:10:45 am »
The point is I guess that the result of ?: can be an lvalue assuming arguments 2 and 3 are.

This is only allowed in C++, not C.  I'm not sure what motivation, if any, lead to the change.

It compiles ~ fine in gcc 4.2/2007

Code: [Select]
#include <stdio.h>

int main (int argc, char *argv[]) {
    int a=  0, b = 0;
    (argc == 2 ? a : b) += 5;
    printf("%i %i\n",a,b);
    return 0;
}

jorge@unibody:~/kk$ gcc --version
i686-apple-darwin10-llvm-gcc-4.2 (GCC) 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.6)
Copyright (C) 2007 Free Software Foundation, Inc.

jorge@unibody:~/kk$ gcc kk.c -o kk.out
kk.c: In function ‘main’:
kk.c:5: warning: target of assignment not really an lvalue; this will be a hard error in the future
jorge@unibody:~/kk$ ./kk.out
0 5
jorge@unibody:~/kk$ ./kk.out 1
5 0
jorge@unibody:~/kk$


Interesting. gcc-4.8 could  not be tricked.

Code: [Select]
$ cat > ternop.c
#include <stdio.h>

int main (int argc, char *argv[]) {
    int a=  0, b = 0;
    (argc == 2 ? a : b) += 5;
    printf("%i %i\n",a,b);
    return 0;
}
$ make ternop
cc     ternop.c   -o ternop
ternop.c: In function ‘main’:
ternop.c:5:25: error: lvalue required as left operand of assignment
     (argc == 2 ? a : b) += 5;
                         ^
make: ** [ternop] Erro 1

g++-4.8 has no problem with it. As expected.

Code: [Select]
$ mv ternop.c ternop.cpp
$ make ternop
g++     ternop.cpp   -o ternop
$ ./ternop
0 5
$ ./ternop 1
5 0
« Last Edit: September 12, 2018, 05:13:23 am by bsfeechannel »
 

Offline nfmax

  • Super Contributor
  • ***
  • Posts: 1560
  • Country: gb
Re: An 'interesting' thing you can do in C++
« Reply #64 on: September 12, 2018, 07:55:07 am »
It's not about "does not understand", but how much effort is needed to comprehend particular piece of code.

You don't really need to do investigative work on the code.

When you design something, you don't design the code, you design data structures, algorithms, protocols etc. Then, once the design is done, you implement it. You can implement it in C, in other language (if you have a compiler), in assembler, whatever you see fit. Except trivial cases, the design is worth more than the implementation. If the design is worthless, the code is worthless too.

The next person who's going to work on the code needs to understand the design. The design may be immediately obvious from the code, but it may not, in which case you need comments, documents etc. Once you understand the design, you can work with the code rather easily. But before you understand the design, you have zero chance of understanding the code.

If you "inherited" code with unknown design, you can, of course, decipher the code and figure out the design. However, this is a lot of work. And after all this work you may find out that the design was mediocre and wasn't worth the investigative efforts. Often, it is much easier to abandon the code right away, re-design and re-write. But, the company which owns the code regards the code itself as an asset which they paid for and cannot abandon it for nothing. Thus, the company will not want to re-design and re-write, hence hours and hours of tedious work figuring out the code, trying to do some changes, often with unpredictable side effects. Such frankensteiny approach makes code more complicated, and often worse than the original. The code also gets more expensive, because all the countless hours spent on the unruly code are counted in. The company will value such code even more and will have even less desire to re-design and re-write, so the horrors go through years, through newly hired programmers, with no chance to stop. Meanwhile, parted from the original design, the code gets worse and worse, and working with it gets harder and harder.

Does it really have anything to do with specific constructs used in the code? I don't think so.
The problem is the design is what the program is intended to do, whereas the code is what it actually does. They are not necessarily the same thing.
 
The following users thanked this post: Mr. Scram

Offline nfmax

  • Super Contributor
  • ***
  • Posts: 1560
  • Country: gb
Re: An 'interesting' thing you can do in C++
« Reply #65 on: September 12, 2018, 08:03:34 am »
For what it's worth, I'm a long-time C programmer and had no trouble at all understanding what the code in OP did. The ternary lvalue is a GCC extension for C, I believe.

I don't get all the squeamishness (for lack of better term) about the ternary operator. It literally looks like you're asking a question and choosing one of two alternatives. Not hard at all.

Templated classes and nested templates, on the other hand... :scared:
It's not the issue of the ternary operator: the problem is with expressions occurring on both sides of assignment operator, that have side effects. Another example, valid in C & C++:
Code: [Select]
int a = 0;
a += ++a;
Will the pre-increment happen before or after the assignment operator takes the 'initial' value of a?
 

Offline ogden

  • Super Contributor
  • ***
  • Posts: 3731
  • Country: lv
Re: An 'interesting' thing you can do in C++
« Reply #66 on: September 12, 2018, 08:52:52 am »
It's not about "does not understand", but how much effort is needed to comprehend particular piece of code.

You don't really need to do investigative work on the code.

Right. What if your do not have to read the code or when you don't have code at all?

:palm:

Obviously code shall be easily readable when you need to understand it, for whatever reason (bugfixing, quality control, taking over the job and so on) which is not that actually important here in this context.
 

Offline Siwastaja

  • Super Contributor
  • ***
  • Posts: 8172
  • Country: fi
Re: An 'interesting' thing you can do in C++
« Reply #67 on: September 12, 2018, 10:18:16 am »
Obviously code shall be easily readable when you need to understand it, for whatever reason (bugfixing, quality control, taking over the job and so on) which is not that actually important here in this context.

Of course.

I think the point NorthGuy is making that we tend to give way too much attention to the readability of small pieces of expressions, while the "big picture" is orders of magnitude more important. Design, and documentation thereof. Data structures, algorithms (which are described in comments preceding functions, and at the top of .c file - what the code does)...

I have had to modify/fix some projects with almost zero "hard-to-read" expressions, with all "style guides" followed, but due to bad higher-level design and documentation, and general bloatness, they have been major PITA - we easily talk about several human-months of work just to fix a trivial bug. OTOH, I have seen projects that reek like "fancy C oneliners", which look visually like crap and every line out of ten requires serious brain power to decode. Guess what? These projects can be orders of magnitude easier to work with, than the previous type!

This is because we are talking about two different problems which are not strongly correlated, and while both are meaningful, they are in a completely different level of being a problem.

Consider fixing a simple bug or adding a trivial feature by a fairly experienced outsider. A broken-by-design implementation with neat coding style easily takes 100-200 hours to do anything with; a properly designed, but crudely written ?:*(++[]--)&* mess may take 10 hours of brain pain to do the same. In an ideal world, an ideal implementation would be studied and fixed in a few hours.

- - -

When in university, I was disappointed at the basic programming courses that mostly focused on bashing "goto" and the ?: operator, trying to prove that ?: automatically and always generates unreadable code; while things like higher-level software design, unit design and testing, documenting what the code is doing in the comments was completely missing from the course.

"Software design" was a separate course, of course, but it was all about writing long user case documents (with little touch to the actual user or the actual coder), drawing UML diagrams and generating hundreds of pages of free-form textual representation. There is a glaring canyon between these two worlds:

1) Abstract, very high level "design" world, often not performed by actual coders, nor someone close to actual end-users. A lot of word documents and powerpoint slides. UML class generation happens with too little surface to the actual implementation, in a waterfall model (first two years drawing UML diagrams, then two years writing the implementation).

3) Implementation of said model (which cannot be modified at that point), where things like ?: operators or using "break" are The Evil, and if the end result is unmaintainable mess, it's not because of 1), but because of the bad coder who used ?: operator.

I can see this sounds quite extreme, but this line of thinking really happens and we really did see it in university.

I left 2) out. It would be a practical level of mid-level design, performed by the coders who are responsible for writing the code. There, the programmer thinks about their data structures, is allowed to modify the higher-level implementation specification, is given freedom and responsibility of designing the class structure, documents their modules and functions in the source code comments (not Word document), to make the code readable as a whole. And not only readable - but small and efficient, something that can only be done when the person closest to the computer running the resulting binary is allowed to participate in the design.

Single "hard to read" constructs are a ridiculously minor detail in this big picture.

Of course, a good programmer makes a good design, documented properly, and, in addition, doesn't produce a single line of hard-to-read *?:&[++--] code.

On the other hand, banning certain constructs never helps anyone produce better code, because the better code exists on a higher level than that. If a certain person produces total unreadable crap, after banning the most ugly constructs, the code will still be crap; only a slight improvement is seen. But now it passes the stupidly simple and trivial corporate "style requirements", and we can pretend everything is OK.

There is a case of experienced programmers sometimes using constructs they understand very well, but beginners have trouble with. Banning such constructs may improve code readability, but very slightly - after all, the beginner learns these constructs fairly quickly because they are just simple syntax, and their number if very limited - they can be learned easily, unlike complex computer program design, which is a difficult task.

The world is full of totally shitty computer programs, yet the discussion about the reasons always ends up to some trivial syntactical detail which is almost meaningless in the big picture.
« Last Edit: September 12, 2018, 10:25:53 am by Siwastaja »
 
The following users thanked this post: amyk, splin, MK14

Online newbrain

  • Super Contributor
  • ***
  • Posts: 1719
  • Country: se
Re: An 'interesting' thing you can do in C++
« Reply #68 on: September 12, 2018, 01:02:17 pm »
Another example, valid in C & C++:
Code: [Select]
int a = 0;
a += ++a;
:palm: No.
The syntax is correct, granted.
But this not valid C or C++ in any standard revision, as it is the textbook example of undefined behaviour.

E.g., from the C99 standard, Annex J.2:
Quote
Between  two sequence  points,  an  object  is  modified  more  than  once,  or  is  modified and the prior value is read other than to determine the value to be stored (6.5).

In this example 'a' is clearly modified twice, and the expression does not contain any internal sequence point.

The ?: ternary operator, on the contrary, has a sequence point at the '?', so your original example:
Code: [Select]
(++ptr == 18 ? a : b ) = ptr--;is perfectly defined.

Would I write code like this? Maybe under torture. But it's correct code nonetheless.
« Last Edit: September 12, 2018, 01:54:25 pm by newbrain »
Nandemo wa shiranai wa yo, shitteru koto dake.
 

Offline nfmax

  • Super Contributor
  • ***
  • Posts: 1560
  • Country: gb
Re: An 'interesting' thing you can do in C++
« Reply #69 on: September 12, 2018, 01:34:04 pm »
In C, the first example is valid (compiles with warnings) but has undefined results. The second is not valid (fails to compile). It is valid C++, but still generates a warning because the value of ptr is modified on both sides of the assignment statement, and neither C nor C++ guarantees the order of modification.
« Last Edit: September 12, 2018, 01:41:43 pm by nfmax »
 

Offline Mr. Scram

  • Super Contributor
  • ***
  • Posts: 9810
  • Country: 00
  • Display aficionado
Re: An 'interesting' thing you can do in C++
« Reply #70 on: September 12, 2018, 02:02:46 pm »
Of course.

I think the point NorthGuy is making that we tend to give way too much attention to the readability of small pieces of expressions, while the "big picture" is orders of magnitude more important. Design, and documentation thereof. Data structures, algorithms (which are described in comments preceding functions, and at the top of .c file - what the code does)...

I have had to modify/fix some projects with almost zero "hard-to-read" expressions, with all "style guides" followed, but due to bad higher-level design and documentation, and general bloatness, they have been major PITA - we easily talk about several human-months of work just to fix a trivial bug. OTOH, I have seen projects that reek like "fancy C oneliners", which look visually like crap and every line out of ten requires serious brain power to decode. Guess what? These projects can be orders of magnitude easier to work with, than the previous type!

This is because we are talking about two different problems which are not strongly correlated, and while both are meaningful, they are in a completely different level of being a problem.

Consider fixing a simple bug or adding a trivial feature by a fairly experienced outsider. A broken-by-design implementation with neat coding style easily takes 100-200 hours to do anything with; a properly designed, but crudely written ?:*(++[]--)&* mess may take 10 hours of brain pain to do the same. In an ideal world, an ideal implementation would be studied and fixed in a few hours.

- - -

When in university, I was disappointed at the basic programming courses that mostly focused on bashing "goto" and the ?: operator, trying to prove that ?: automatically and always generates unreadable code; while things like higher-level software design, unit design and testing, documenting what the code is doing in the comments was completely missing from the course.

"Software design" was a separate course, of course, but it was all about writing long user case documents (with little touch to the actual user or the actual coder), drawing UML diagrams and generating hundreds of pages of free-form textual representation. There is a glaring canyon between these two worlds:

1) Abstract, very high level "design" world, often not performed by actual coders, nor someone close to actual end-users. A lot of word documents and powerpoint slides. UML class generation happens with too little surface to the actual implementation, in a waterfall model (first two years drawing UML diagrams, then two years writing the implementation).

3) Implementation of said model (which cannot be modified at that point), where things like ?: operators or using "break" are The Evil, and if the end result is unmaintainable mess, it's not because of 1), but because of the bad coder who used ?: operator.

I can see this sounds quite extreme, but this line of thinking really happens and we really did see it in university.

I left 2) out. It would be a practical level of mid-level design, performed by the coders who are responsible for writing the code. There, the programmer thinks about their data structures, is allowed to modify the higher-level implementation specification, is given freedom and responsibility of designing the class structure, documents their modules and functions in the source code comments (not Word document), to make the code readable as a whole. And not only readable - but small and efficient, something that can only be done when the person closest to the computer running the resulting binary is allowed to participate in the design.

Single "hard to read" constructs are a ridiculously minor detail in this big picture.

Of course, a good programmer makes a good design, documented properly, and, in addition, doesn't produce a single line of hard-to-read *?:&[++--] code.

On the other hand, banning certain constructs never helps anyone produce better code, because the better code exists on a higher level than that. If a certain person produces total unreadable crap, after banning the most ugly constructs, the code will still be crap; only a slight improvement is seen. But now it passes the stupidly simple and trivial corporate "style requirements", and we can pretend everything is OK.

There is a case of experienced programmers sometimes using constructs they understand very well, but beginners have trouble with. Banning such constructs may improve code readability, but very slightly - after all, the beginner learns these constructs fairly quickly because they are just simple syntax, and their number if very limited - they can be learned easily, unlike complex computer program design, which is a difficult task.

The world is full of totally shitty computer programs, yet the discussion about the reasons always ends up to some trivial syntactical detail which is almost meaningless in the big picture.

Why do you feel "break" is evil? When applied correctly it can make code more legible. The MISRA coding guidelines have been updated to the same effect. I agree that using "break" in long or nested loops can be confusing and obfuscating.
 

Online newbrain

  • Super Contributor
  • ***
  • Posts: 1719
  • Country: se
Re: An 'interesting' thing you can do in C++
« Reply #71 on: September 12, 2018, 02:19:42 pm »
In C, the first example is valid (compiles with warnings) but has undefined results. The second is not valid (fails to compile). It is valid C++, but still generates a warning because the value of ptr is modified on both sides of the assignment statement, and neither C nor C++ guarantees the order of modification.
Of course the second example is only for (recent) C++, no doubt about it: in C the ? operator does not return a modifiable lvalue.

What we disagree upon is the "valid" adjective for the first example, unfortunately the standard does not define it unambiguously.
That code violates a "shall" (the one in the second clause of 6.5), so it has undefined behaviour - I think this is not in dispute.
According to my reading of Ch 4, a program that contains UB is neither (strictly) conforming nor correct.
This leaves us with only syntactical validity, i.e. the compiler can make sense of the sequence of symbols - it's even kind enough to emit a non mandatory diagnostic for the UB - but I would not call it "valid".

Moreover, note 8 of 5.1.1.3 clearly states that implementations can successfully translate an invalid program.

I would simply call it wrong.

But we are probably just saying the same thing, just with different words... :-//

BTW: I've always been puzzled by people who expects a specific result from code like that, to my mind it  has always looked meaningless, even before reading the standard. |O

Nandemo wa shiranai wa yo, shitteru koto dake.
 

Offline nfmax

  • Super Contributor
  • ***
  • Posts: 1560
  • Country: gb
Re: An 'interesting' thing you can do in C++
« Reply #72 on: September 12, 2018, 02:30:29 pm »
I don't actually recommend using code like either of the two examples!  ;)

Moreover, note 8 of 5.1.1.3 clearly states that implementations can successfully translate an invalid program.

The take home from this: treat all warnings as errors (since the warning message is required by section 5.1.1.3 itself).
 
The following users thanked this post: newbrain

Offline Siwastaja

  • Super Contributor
  • ***
  • Posts: 8172
  • Country: fi
Re: An 'interesting' thing you can do in C++
« Reply #73 on: September 12, 2018, 02:35:56 pm »
Why do you feel "break" is evil?

Totally beats me. That's what everybody were taught, on compulsory programming introduction courses (in C++), in the university I attended. (To be fair, we were actually taught that "break" is not as Evil as goto or ?:, but still a bit Evil.)

Of course, writing practical code in real life while completely avoiding ?: or break or even goto is nearly impossible, or at least detrimental to code quality and readability, as well as psychological productivity.

That said, now I remembered an additional detail: they had an exception that it is allowed to use break inside switch-case, but only there. They figured out switch-case doesn't work without it, and were not bold enough to claim switch-case is Evil.

This is all  :-DD , but at the same time, it's quite  :-- as well.

(Also note that creating such "order" of Evil-ity is ridiculous. In some contexts, goto results in much more readable result than break, yet it's down the list of things to be "frowned upon". It's always dependent on usage. But I guess we have no debate about this here.)
« Last Edit: September 12, 2018, 02:41:03 pm by Siwastaja »
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3146
  • Country: ca
Re: An 'interesting' thing you can do in C++
« Reply #74 on: September 12, 2018, 04:17:28 pm »
Moreover, note 8 of 5.1.1.3 clearly states that implementations can successfully translate an invalid program.

I would simply call it wrong.

Compiler may not know that the program is invalid. For example:

Code: [Select]
x[a] = x[b]++;
This code is invalid (and result is undefined) only if a == b. Otherwise, the code is absolutely fine. It would be possible to come up with rules which make the result always defined. But this would be a burden on the compiler. The compiler would have to generate the code which is less efficient to handle many unusual situations which would never happen in real life. Instead, the standard deems the result undefined to free up the compiler and let it generate more efficient code. At the same time, the programmer's mind is freed from remembering extra rules. It is up to the programmer to ensure that the situation where a == b never happens.

It is the same as division by zero - the compiler simply generates the division code and it is up to you to make sure that you don't divide by zero.

If you feel the checks are needed, it is up to you to remove the ambiguity, such as:

Code: [Select]
y = x[b]++;
x[a] = y;

 
The following users thanked this post: newbrain

Offline nfmax

  • Super Contributor
  • ***
  • Posts: 1560
  • Country: gb
Re: An 'interesting' thing you can do in C++
« Reply #75 on: September 12, 2018, 05:02:25 pm »
Ah yes, the aliasing problem. Interestingly, with default switches this code doesn't generate a warning. On my system, the assignment occurs after the post-increment, thereby clobbering it.

Code: [Select]
byrd:ctest max$ gcc --version
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/c++/4.2.1
Apple LLVM version 9.1.0 (clang-902.0.39.2)
Target: x86_64-apple-darwin17.7.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin

 I think we can add the pre/post increment/decrement operators to the Dodgy C Constructs list! You can always write:
Code: [Select]
array[a] = array[b];
array[b] = array[b] + 1;
Which is unambiguous
 

Online newbrain

  • Super Contributor
  • ***
  • Posts: 1719
  • Country: se
Re: An 'interesting' thing you can do in C++
« Reply #76 on: September 12, 2018, 05:38:45 pm »
Moreover, note 8 of 5.1.1.3 clearly states that implementations can successfully translate an invalid program.

I would simply call it wrong.

Compiler may not know that the program is invalid. For example:
[...]
Of course!

I think we can add the pre/post increment/decrement operators to the Dodgy C Constructs list!
I don't see anything dodgy in those operators, following the line of thought "It's dodgy as it can result in undefined behaviour" one could also include all the arithmetic operators in the category.

As NorthGuy correctly described, UB is in most cases not something that resulted from sloppy thinking but enabled the compilers and the resulting code not to be burdened by excessive runtime checks, trading safety for efficiency.
Fortran, for example, has a different set of rules for aliasing, allowing an even higher degree of shortcuts and optimizations (and biting my ass more than once in faraway times  ::)).

If one wants thoughtless safety, other languages are more suitable.
Nandemo wa shiranai wa yo, shitteru koto dake.
 

Online RoGeorge

  • Super Contributor
  • ***
  • Posts: 6202
  • Country: ro
Re: An 'interesting' thing you can do in C++
« Reply #77 on: September 12, 2018, 05:45:44 pm »
Compiler may not know that the program is invalid. For example:

Code: [Select]
x[a] = x[b]++;
This code is invalid (and result is undefined) only if a == b.

If a = b, then the value of x[a] will remain unchanged.
The rule I know is that the right side of an assignment is evaluated first, then the left side, then the assignment is made.

x[a] = x[a]++ is the same as n = n++. Let's say n=10.
- First we read the value (10) stored at address n, in order to further use it in the calculation of the right side expression. Other said, we make a copy of n.
- Then, we increment the content of address n. Now n will contain the value 11
- Then we continue the evaluation of the right side expression (in our case, nothing to do), so the right side result is 10. In memory, at address n is stored 11.
- Now, it's time to evaluate the left hand side of the assignment (For n=n++, there is nothing to evaluate in the left side. For x[y]=x[z]++, in the left side we will evaluate &x+y*sizeoff(x) )
- Then, the assignment: Our n, which is now 11, will receive the value calculated in the right hand side, which is 10.

So, we will end up with an unchanged value. No undefined situation. What am I missing?
Isn't the right side of an assignment always evaluated first?
« Last Edit: September 12, 2018, 05:53:16 pm by RoGeorge »
 

Offline dmills

  • Super Contributor
  • ***
  • Posts: 2093
  • Country: gb
Re: An 'interesting' thing you can do in C++
« Reply #78 on: September 12, 2018, 05:59:04 pm »
That is NOT the rule in C!

The problem comes from the fact that all side effects are only guaranteed to be evaluated before the next sequence point, and an assignment (=) is NOT a sequence point!

Consider the canonically broken i = i++;
There is only ONE sequence point, the semi colon.

i will be assigned to a temporary.
i will be incremented sometime before that sequence point.
the temporary will be assigned to i sometime before that sequence point, but there is no guarantee about which order these last two operations will occur in.

Here be Nasal Demons.

Regards, Dan.
 
The following users thanked this post: newbrain

Offline glarsson

  • Frequent Contributor
  • **
  • Posts: 814
  • Country: se
Re: An 'interesting' thing you can do in C++
« Reply #79 on: September 12, 2018, 06:00:37 pm »
No undefined situation. What am I missing?
Isn't the right side of an assignment always evaluated first?
You are missing what is written in the C standard. Left vs. Right does not matter. The simple rule is that you may not modify  s variable more than once between sequence points. The assignment is not a sequence point; the next one is at the semicolon.

For a=a++; the compiler is allowed to Instruct the processor to execute a=a and a++ at the same time for efficiency. In this case this creates a race condition or nasal daemons.
 
The following users thanked this post: newbrain

Offline GeorgeOfTheJungle

  • Super Contributor
  • ***
  • !
  • Posts: 2699
  • Country: tr
Re: An 'interesting' thing you can do in C++
« Reply #80 on: September 12, 2018, 06:04:00 pm »
Yep, that makes sense IMO, and in the same vein (1st evaluate the right side, then the left side)

Code: [Select]
#include <stdio.h>

int main (int argc, char *argv[]) {
    int a=  0, b = 0;
    a+= ++a;
    b+= b++;
    printf("%i,%i\n",a,b);
    return 0;
}

Gives 2,1. At least with my compiler!

Then there's whatever the C Standard says, but out of comp.lang.c and comp.unix.programmer, who reads that?  >:D
« Last Edit: September 12, 2018, 06:10:35 pm by GeorgeOfTheJungle »
The further a society drifts from truth, the more it will hate those who speak it.
 

Offline ralphrmartin

  • Frequent Contributor
  • **
  • Posts: 480
  • Country: gb
    • Me
Re: An 'interesting' thing you can do in C++
« Reply #81 on: September 12, 2018, 06:19:03 pm »
You could do this in Algol68, as in 1968...
 

Offline glarsson

  • Frequent Contributor
  • **
  • Posts: 814
  • Country: se
Re: An 'interesting' thing you can do in C++
« Reply #82 on: September 12, 2018, 06:21:04 pm »
Gives 2,1. At least with my compiler!
That's stupid.

You might get another result in the next program because the compiler is allowed to generate different code depending on circumstances, e.g. if you add more complex code near the ub-invoking code, the compiler might run out of registers and generate different code.
 
The following users thanked this post: GeorgeOfTheJungle

Online newbrain

  • Super Contributor
  • ***
  • Posts: 1719
  • Country: se
Re: An 'interesting' thing you can do in C++
« Reply #83 on: September 12, 2018, 06:24:32 pm »
Then there's whatever the C Standard says, but out of comp.lang.c and comp.unix.programmer, who reads that?  >:D
|O Who wants working code.

The very case of a[ i] = a[i++] changed behaviour in a recent(ish) update of gcc, at the same level of optimization.
I still remember my friend complaining loudly that "the new gcc in Ubuntu is broken"...

Edit: [ i ] eaten by dog forum SW
« Last Edit: September 12, 2018, 06:57:05 pm by newbrain »
Nandemo wa shiranai wa yo, shitteru koto dake.
 

Offline GeorgeOfTheJungle

  • Super Contributor
  • ***
  • !
  • Posts: 2699
  • Country: tr
Re: An 'interesting' thing you can do in C++
« Reply #84 on: September 12, 2018, 06:26:30 pm »
Gives 2,1. At least with my compiler!
That's stupid.

$gcc --version
Copyright (C) 2007 Free Software Foundation, Inc.

Go tell them!
The further a society drifts from truth, the more it will hate those who speak it.
 

Online newbrain

  • Super Contributor
  • ***
  • Posts: 1719
  • Country: se
Re: An 'interesting' thing you can do in C++
« Reply #85 on: September 12, 2018, 06:28:00 pm »
Gives 2,1. At least with my compiler!
That's stupid.

$gcc --version
Copyright (C) 2007 Free Software Foundation, Inc.

Go tell them!
Obvious troll is obvious.
Nandemo wa shiranai wa yo, shitteru koto dake.
 

Offline glarsson

  • Frequent Contributor
  • **
  • Posts: 814
  • Country: se
Re: An 'interesting' thing you can do in C++
« Reply #86 on: September 12, 2018, 06:41:29 pm »
Go tell them!
No. I didn't say the compiler was stupid. It is allowed to give that result. I meant that it is stupid to try to figure out how a compiler  handles undefined behavior. That information is useless as you shouldn't use it/depend on it.
 
The following users thanked this post: GeorgeOfTheJungle

Offline GeorgeOfTheJungle

  • Super Contributor
  • ***
  • !
  • Posts: 2699
  • Country: tr
Re: An 'interesting' thing you can do in C++
« Reply #87 on: September 12, 2018, 06:52:37 pm »
But the C standard != gcc documentation. Perhaps it's un-undefined somewhere there (in gcc). My gcc 4.2 also lets me use an rvalue as lvalue (the OP code runs fine), and that's not in the standard, so... what happens when UB (by the std) becomes defined somewhere else (e.g. gcc)? Can one use that or it's a sin?

Edit: Not this case.

$ gcc -O3 -Wsequence-point kk.c
kk.c: In function ‘main’:
kk.c:5: warning: operation on ‘a’ may be undefined
kk.c:6: warning: operation on ‘b’ may be undefined
« Last Edit: September 12, 2018, 07:05:55 pm by GeorgeOfTheJungle »
The further a society drifts from truth, the more it will hate those who speak it.
 

Online RoGeorge

  • Super Contributor
  • ***
  • Posts: 6202
  • Country: ro
Re: An 'interesting' thing you can do in C++
« Reply #88 on: September 12, 2018, 06:55:13 pm »
Now I noticed that the title says C++, and I was thinking about C all the time. I don't know about C++. My bad, sorry.

Please let me ask again: I always thought that in C (not C++), the postfix ++ is an atomic read-modify-write operation. Being atomic will also imply to calculate the increment on the spot, the ++ can not be postponed until the next ";". Example:
x=10;
y=x++ + x++;
will end IMO with x is 12, and y is 21 (NOT 20).

Is this correct for C?
Is this undefined for C++?

Online newbrain

  • Super Contributor
  • ***
  • Posts: 1719
  • Country: se
Re: An 'interesting' thing you can do in C++
« Reply #89 on: September 12, 2018, 07:04:15 pm »
Now I noticed that the title says C++, and I was thinking about C all the time. I don't know about C++. My bad, sorry.

Please let me ask again: I always thought that in C (not C++), the postfix ++ is an atomic read-modify-write operation. Being atomic will also imply to calculate the increment on the spot, the ++ can not be postponed until the next ";". Example:
x=10;
y=x++ + x++;
will end IMO with x is 12, and y is 21 (NOT 20).

Is this correct for C?
Is this undefined for C++?
No, it's not atomic. Its only guarantee is that the side effect (increment) will happen as if it was carried out before the next sequence point.
If the incremented variable is volatile, we have the guarantee that it actually happens before the next sequence point.
(But I should check the fine print).

So, it's never correct, in neither C or C++.

BTW, this is really, really, the most common (and asked about) case of UB, and it's clearly spelled out and described in the C standard as such (6.5, J.2).

Maybe GeorgeOfTheJungle is right, and I'm the only one who enjoys reading the standard (and the rationale! that was really a good read!) :-[
Nandemo wa shiranai wa yo, shitteru koto dake.
 

Offline Siwastaja

  • Super Contributor
  • ***
  • Posts: 8172
  • Country: fi
Re: An 'interesting' thing you can do in C++
« Reply #90 on: September 12, 2018, 07:21:44 pm »
Even if you didn't want to read the standard, these particular Undefined Behavior (as well as aliasing rules) examples are discussed to death :horse: everywhere on the 'net; Google easily gives you answers, rationale, and discussion.

C is an interesting language because it's quite braindead..ish, and the standard more or less sucks; but it's not catastrophic enough to be unusable, and most "elegant" "replacements" end up being more fundamentally problematic (or just don't gain traction); so C remains surprisingly usable decade after decade, in unforeseeable future; and I don't think it's completely due to legacy code. A lot of completely new projects, even from young, new developers, spawn in C all the time. (As a side note, I almost exclusively write in C, as well.)

Same is true with C++, except with 100x more bloat, 100x more uncertainty and 100x more issues - and even less "elegance". Unlike C, where the horror show has stalled to a stable state, in C++, the horrors continue developing to the Next Levels all the time, directed by a very productive committee. Somehow, it still remains both usable and popular as well. This is almost magical, IMHO.
« Last Edit: September 12, 2018, 07:24:54 pm by Siwastaja »
 

Offline GeorgeOfTheJungle

  • Super Contributor
  • ***
  • !
  • Posts: 2699
  • Country: tr
Re: An 'interesting' thing you can do in C++
« Reply #91 on: September 12, 2018, 07:39:07 pm »
http://gcc.gnu.org/onlinedocs/gcc-3.1/gcc/Warning-Options.html

Quote from:  Free Software Foundation
-Wsequence-point
Warn about code that may have undefined semantics because of violations of sequence point rules in the C standard.
The C standard defines the order in which expressions in a C program are evaluated in terms of sequence points, which represent a partial ordering between the execution of parts of the program: those executed before the sequence point, and those executed after it. These occur after the evaluation of a full expression (one which is not part of a larger expression), after the evaluation of the first operand of a &&, ||, ? : or , (comma) operator, before a function is called (but after the evaluation of its arguments and the expression denoting the called function), and in certain other places. Other than as expressed by the sequence point rules, the order of evaluation of subexpressions of an expression is not specified. All these rules describe only a partial order rather than a total order, since, for example, if two functions are called within one expression with no sequence point between them, the order in which the functions are called is not specified. However, the standards committee have ruled that function calls do not overlap.

It is not specified when between sequence points modifications to the values of objects take effect. Programs whose behavior depends on this have undefined behavior; the C standard specifies that "Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be read only to determine the value to be stored.". If a program breaks these rules, the results on any particular implementation are entirely unpredictable.

Examples of code with undefined behavior are a = a++;, a[n] = b[n++] and a[i++] = i;. Some more complicated cases are not diagnosed by this option, and it may give an occasional false positive result, but in general it has been found fairly effective at detecting this sort of problem in programs.

The present implementation of this option only works for C programs. A future implementation may also work for C++ programs.

The C standard is worded confusingly, therefore there is some debate over the precise meaning of the sequence point rules in subtle cases. Links to discussions of the problem, including proposed formal definitions, may be found on our readings page, at http://gcc.gnu.org/readings.html.
The further a society drifts from truth, the more it will hate those who speak it.
 

Offline glarsson

  • Frequent Contributor
  • **
  • Posts: 814
  • Country: se
Re: An 'interesting' thing you can do in C++
« Reply #92 on: September 12, 2018, 07:44:31 pm »
C is not braindead unless you have the wrong expectations. It was designed to write operating systems, device drivers etc. It will live on for a long time as it is very hard to design a competing language that is sufficiently better.

In my view C is like a small sports car with manual gearbox, no ABS, no airbags, no traction control etc. If you can handle the challenge you will drive very fast on the twisty roads, but it will not be a SUV with all the latest driver aids. If you need that kind of support you need a different language, e.g. Ada. :-)
 
The following users thanked this post: Siwastaja, newbrain, drussell

Offline GeorgeOfTheJungle

  • Super Contributor
  • ***
  • !
  • Posts: 2699
  • Country: tr
Re: An 'interesting' thing you can do in C++
« Reply #93 on: September 12, 2018, 07:48:31 pm »
Maybe GeorgeOfTheJungle is right, and I'm the only one who enjoys reading the standard (and the rationale! that was really a good read!) :-[

I have never read it. In my defence, there was no such thing when I started (1986) programming in C (only the C book by Kernighan). But I've had to read the EcmaScript one more than once, and that's a brick.
The further a society drifts from truth, the more it will hate those who speak it.
 

Offline glarsson

  • Frequent Contributor
  • **
  • Posts: 814
  • Country: se
Re: An 'interesting' thing you can do in C++
« Reply #94 on: September 12, 2018, 07:55:36 pm »
I have read the C standard. I bought a copy from ANSI. Sometimes I think I'm the only one that have read it...
 

Online newbrain

  • Super Contributor
  • ***
  • Posts: 1719
  • Country: se
Re: An 'interesting' thing you can do in C++
« Reply #95 on: September 12, 2018, 08:04:26 pm »
I have read the C standard. I bought a copy from ANSI. Sometimes I think I'm the only one that have read it...
Ant that makes two!
Sweden - Rest of the world: 2 - 0  :-DD
Nandemo wa shiranai wa yo, shitteru koto dake.
 

Offline GeorgeOfTheJungle

  • Super Contributor
  • ***
  • !
  • Posts: 2699
  • Country: tr
Re: An 'interesting' thing you can do in C++
« Reply #96 on: September 12, 2018, 08:17:29 pm »
Wow, this is even cool, look:

Quote
    If two settings of the same object cannot be proven to be disjoint in time, the evaluation is considered undefined.  Example:
            (x = 1) * (x = 2)
(from http://www.open-std.org/jtc1/sc22/wg14/www/docs/n927.htm)

Code: [Select]
#include <stdio.h>

int main () {
    int a, b;
    b= (a = 1) * (a = 2);
    printf("%i,%i\n", a, b);
    return 0;
}

$ gcc -O0 -Wsequence-point kk.c -o kk.out
kk.c: In function ‘main’:
kk.c:5: warning: operation on ‘a’ may be undefined
$ ./kk.out
2,4

With a well chosen bunch of these ~WTFs someone could write a winner for the obfuscated C contest!
« Last Edit: September 13, 2018, 12:42:29 pm by GeorgeOfTheJungle »
The further a society drifts from truth, the more it will hate those who speak it.
 

Offline ejeffrey

  • Super Contributor
  • ***
  • Posts: 3719
  • Country: us
Re: An 'interesting' thing you can do in C++
« Reply #97 on: September 12, 2018, 08:29:26 pm »
$ gcc -O3 -Wsequence-point kk.c
kk.c: In function ‘main’:
kk.c:5: warning: operation on ‘a’ may be undefined
kk.c:6: warning: operation on ‘b’ may be undefined

Note that you can't rely on this warning.  The compiler will try to help if you ask but it can't identify all undefined behavior.

Quote
so... what happens when UB (by the std) becomes defined somewhere else (e.g. gcc)

gcc doesn't define the behavior.  When you write code with potentially undefined behavior gcc will pick some concrete implementation that is correct if no undefined behavior actually happens.  It makes no promises to do the same thing every time and in every circumstance.  That's the devil of undefined behavior: it might work the way you expect most of the time but can change based on unpredictable circumstances.

The fundamental issue here is that there are a lot of machine optimizations that are non-obvious, especially on modern superscalar processors.  If you want the best performance you have to give the compiler some freedom to rearrange things without changing the meaning of the code.  Its hard to do this without creating some undefined behavior.

The real problem is with aliasing.  a = a++ is undefined by the standard but would be easy for the compiler to detect and do something sensible.  The problem is when you have a = b++ where 'a' and 'b' are expressions that might or might not alias to the same variable.  The C standard says that the compiler has to assume that any two expressions of the same type might be aliases (unless it can prove otherwise) but that only blocks reordering across sequence points.  Between sequence points it is your job to make sure that you don't violate the rules.
 

Online RoGeorge

  • Super Contributor
  • ***
  • Posts: 6202
  • Country: ro
Re: An 'interesting' thing you can do in C++
« Reply #98 on: September 12, 2018, 08:29:38 pm »
I'm not a programmer, so I go to standards only in very rare occasions, when something does not work how I expected. So far, my thumb rules kept me safe, especially because I don't do stunts, yet I was so wrong. Thank you all for helping me clarify this.

Volatile or not, it does not work how I supposed.
I just tested now, and to my surprise if a=10, then any of the following
  • b=a + a++
  • b=a++ + a
  • b=a++ + a++
returns b as 21, no matter if a is volatile or not, which is quite a surprise for me. Thanks again!

Especially the first one, seems straight broken. I would have swear it should return 20, not 21.  :-[

Online newbrain

  • Super Contributor
  • ***
  • Posts: 1719
  • Country: se
Re: An 'interesting' thing you can do in C++
« Reply #99 on: September 12, 2018, 09:42:20 pm »
I'm not a programmer, so I go to standards only in very rare occasions, when something does not work how I expected. So far, my thumb rules kept me safe, especially because I don't do stunts, yet I was so wrong. Thank you all for helping me clarify this.

Volatile or not, it does not work how I supposed.
I just tested now, and to my surprise if a=10, then any of the following
  • b=a + a++
  • b=a++ + a
  • b=a++ + a++
returns b as 21, no matter if a is volatile or not, which is quite a surprise for me. Thanks again!

Especially the first one, seems straight broken. I would have swear it should return 20, not 21.  :-[
Sorry for bringing up the volatile qualifier, is a bit of a red herring in this case.

What I poorly tried to explain is that in x++ the actual increment might happen in any moment, even after the semicolon sequence point, as long as the result of the program is the same (when I check x sometimes after this expression, I find it incremented).
If x is volatile, this side effect is guaranteed to happen before the sequence point.
From "inside" the program, in this case, the volatile qualifier makes absolutely no difference.
See also the last paragraph of ejeffrey's post.

I don't see why you would expect the first case to be 20, there is no strictly defined right to left or left to right evaluation order in C (APL, e.g., is strictly right to left, forth left to right).
And no, using parenthesis to force things is useless.

The most important concepts here are:
  • Side effects:
    Things that happen to your variables, such an assignment or an increment, also a read if the object is volatile.
  • Sequence points:
    They represent the anchor points that define the ordering of the side effects.
    Semicolons, but also the ? in the conditional operator, the comma operator, && and ||, function calls.

Clause 2 in 5.1.2.3:
Quote
At certain specified points in the execution sequence called sequence points, all side effects
of previous evaluations shall be complete and no side effects of subsequent evaluations
shall have taken place.

Note that between two sequence points the standard does not impose any ordering requirement.

Don't do stunts (such as the ones you posted), and you'll be mostly safe.
Nandemo wa shiranai wa yo, shitteru koto dake.
 
The following users thanked this post: RoGeorge

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3146
  • Country: ca
Re: An 'interesting' thing you can do in C++
« Reply #100 on: September 12, 2018, 11:14:33 pm »
In my view C is like a small sports car with manual gearbox, no ABS, no airbags, no traction control etc. If you can handle the challenge you will drive very fast on the twisty roads, but it will not be a SUV with all the latest driver aids.

No, that's assembler :)
 
The following users thanked this post: hans

Offline brucehoult

  • Super Contributor
  • ***
  • Posts: 4036
  • Country: nz
Re: An 'interesting' thing you can do in C++
« Reply #101 on: September 12, 2018, 11:23:39 pm »
No undefined situation. What am I missing?
Isn't the right side of an assignment always evaluated first?
You are missing what is written in the C standard. Left vs. Right does not matter. The simple rule is that you may not modify  s variable more than once between sequence points. The assignment is not a sequence point; the next one is at the semicolon.

For a=a++; the compiler is allowed to Instruct the processor to execute a=a and a++ at the same time for efficiency. In this case this creates a race condition or nasal daemons.

No, that's not nasal demons. After "a=a++;", a will either have the same value as before, or will be incremented by 1. There are no other options. The program will not crash. Your computer will not catch on fire. Demons will not fly out of your nose (or your arse). The result is boundedly undefined.
 
The following users thanked this post: hans

Online MK14

  • Super Contributor
  • ***
  • Posts: 4539
  • Country: gb
Re: An 'interesting' thing you can do in C++
« Reply #102 on: September 12, 2018, 11:41:55 pm »
In my view C is like a small sports car with manual gearbox, no ABS, no airbags, no traction control etc. If you can handle the challenge you will drive very fast on the twisty roads, but it will not be a SUV with all the latest driver aids.

No, that's assembler :)

Assembler = Motorbike.
That is why windows can't be written in assembler. Because motorbikes never (usually) have doors, so there is no room for any windows.
 
The following users thanked this post: Siwastaja

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3146
  • Country: ca
Re: An 'interesting' thing you can do in C++
« Reply #103 on: September 12, 2018, 11:50:47 pm »
After "a=a++;", a will either have the same value as before, or will be incremented by 1. There are no other options. The program will not crash. Your computer will not catch on fire. Demons will not fly out of your nose (or your arse). The result is boundedly undefined.

Not sure about C++, but the plain C allows the compiler to do practically anything:

"Possible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message), to terminating a translation or
execution (with the issuance of a diagnostic message)."

Of course, the real compiler will perform the operations one way or another, but it doesn't have to.
 

Offline westfw

  • Super Contributor
  • ***
  • Posts: 4199
  • Country: us
Re: An 'interesting' thing you can do in C++
« Reply #104 on: September 13, 2018, 12:16:56 am »
Quote
Code: [Select]
(argc == 2 ? a : b) += 5;

Quote
For what it's worth, I'm a long-time C programmer and had no trouble at all understanding what the code in OP did.

A agree that this particular example is pretty easy to understand, and indeed my first reaction was more along the lines of "oh?  Didn't that work before?  Oh, right...")
But I don't really see any reason to specifically ADD the ability to do this to the language specification, either.
Haven't we outgrown the whole "COBOL is much too verbose; we're going to write APL/Forth/C so that you'll have to type a lot less!" thing?
 

Offline Siwastaja

  • Super Contributor
  • ***
  • Posts: 8172
  • Country: fi
Re: An 'interesting' thing you can do in C++
« Reply #105 on: September 13, 2018, 06:25:03 am »
In my view C is like a small sports car with manual gearbox, no ABS, no airbags, no traction control etc. If you can handle the challenge you will drive very fast on the twisty roads, but it will not be a SUV with all the latest driver aids.

Not bad!

I'd add that maybe C is like a 70's to 80's Toyota Corolla. Widely used in its simplest form, most people aren't super excited about it, but it does the job fine and economically time after time. At the same time, others have found out you can tune the shit out of it to extract performance and do "tricks" that weren't in the original "marketing" - and doing this is relatively simple. While it doesn't have airbags, it's not the most inherently unsafe thing ever, either.

And, while expensive and fast "sports cars" do exist,  they are heavy, clumsy to also perform everyday tasks with, are black boxes of complexity, and tend to suddenly catch fire while sitting in traffic lights, or just offer so much power in one place that their young, inexperienced owners tend to epidemically crash them (to make headline videos on internet video news sites designed for envious, poor people to laugh at). I don't know which programming language these cars would represent, but IMHO, at least not C. Maybe C++?

Me? I drive a 1988 Toyota Carina II, rusty as hell but does the job, and write in C, rusty as hell but does the job.
« Last Edit: September 13, 2018, 06:40:40 am by Siwastaja »
 
The following users thanked this post: MK14

Online MK14

  • Super Contributor
  • ***
  • Posts: 4539
  • Country: gb
Re: An 'interesting' thing you can do in C++
« Reply #106 on: September 13, 2018, 06:36:37 am »
I'd add that maybe C is like a 70's to 80's Toyota Corolla.

That's good.

So an interpreted/scripted language = Horse and Cart.
Because a Horse and Cart is very simple and somewhat quick to assemble/make. Not fast, by any stretch of the imagination.

VHDL/Verilog
FPGA = Jet Aircraft
ASIC or full custom IC = Space Rocket
 

Online MK14

  • Super Contributor
  • ***
  • Posts: 4539
  • Country: gb
Re: An 'interesting' thing you can do in C++
« Reply #107 on: September 13, 2018, 07:13:39 am »
No, that's not nasal demons. After "a=a++;", a will either have the same value as before, or will be incremented by 1. There are no other options. The program will not crash. Your computer will not catch on fire. Demons will not fly out of your nose (or your arse). The result is boundedly undefined.

The thing is that the compiler, has been designed to a certain defined specification (The C or applicable, standard). So, since the operation is UNDEFINED, the compiler has NOT (necessarily) been designed to include the capabilities to correctly compile such code.

So you can't (with 100% reliability), say "it will always be the same or same plus 1 value, never anything else".
Since you have gone outside of the allowable limits of the compiler (exceeded Absolute Maximum values, if you want a datasheet analogy).
Therefore, absolutely anything can happen.

Just like exceeding the maximum capabilities of a transistor.
The overloaded transistor, may carry on working, it may let out the magic smoke, it may catch on fire and explode.
It may eject a high copper content vapour, which when your mother breathes it in, changes her colour to GREEN, and when you breath in the magic smoke you may cough out terrible demons.
« Last Edit: September 13, 2018, 07:18:04 am by MK14 »
 

Offline GeorgeOfTheJungle

  • Super Contributor
  • ***
  • !
  • Posts: 2699
  • Country: tr
Re: An 'interesting' thing you can do in C++
« Reply #108 on: September 13, 2018, 07:47:58 am »
Nope, I'm with brucehoult on this one, our mothers are safe.
The further a society drifts from truth, the more it will hate those who speak it.
 

Online newbrain

  • Super Contributor
  • ***
  • Posts: 1719
  • Country: se
Re: An 'interesting' thing you can do in C++
« Reply #109 on: September 13, 2018, 08:07:19 am »
Nope, I'm with brucehoult on this one, our mothers are safe.
I'm partially in total disagreement.
Our mothers might be safe, but hyperbole is a man's best friend.

Unfortunately I have lost the example (code, specific version of gcc and flags used) where a similar line was completely ignored by the compiler.
Skipped, no code emitted, no warning.
The result was that a block local variable would keep its random uninitialized value.

Nandemo wa shiranai wa yo, shitteru koto dake.
 
The following users thanked this post: MK14

Offline glarsson

  • Frequent Contributor
  • **
  • Posts: 814
  • Country: se
Re: An 'interesting' thing you can do in C++
« Reply #110 on: September 13, 2018, 08:12:16 am »
No, that's not nasal demons. After "a=a++;", a will either have the same value as before, or will be incremented by 1. There are no other options. The program will not crash. Your computer will not catch on fire. Demons will not fly out of your nose (or your arse).
Anything can happen.
Only fools think that a=a++; is a reasonable thing to write. I don't know what they thing it will accomplish. A more reasonable, but also sinister, situation is when a and a has different names and are pointers pointing at the same variable. On a supetscalar processor the instructions might then be
  move @a,@b
  add @a,@b,1
with both instructions executing at the same time. When both instructions retire and both attempt to update what a points to (@a) at the same time, the processor will detect this and raise some low level exception. If this happens in your nose transplant then nasal daemons is a reasonable result.
 
The following users thanked this post: newbrain, MK14

Offline GeorgeOfTheJungle

  • Super Contributor
  • ***
  • !
  • Posts: 2699
  • Country: tr
Re: An 'interesting' thing you can do in C++
« Reply #111 on: September 13, 2018, 08:32:50 am »
Only fools think that a=a++; is a reasonable thing to write.

That much is clear! (I hope)

I'm partially in total disagreement.

LOL

Quote
The result was that a block local variable would keep its random uninitialized value.

If a was uninitialized before that line, it would have to remain so after it, so that's ok, isn't it?
The further a society drifts from truth, the more it will hate those who speak it.
 

Offline hamster_nzTopic starter

  • Super Contributor
  • ***
  • Posts: 2803
  • Country: nz
Re: An 'interesting' thing you can do in C++
« Reply #112 on: September 13, 2018, 08:44:48 am »
No, that's not nasal demons. After "a=a++;", a will either have the same value as before, or will be incremented by 1. There are no other options. The program will not crash. Your computer will not catch on fire. Demons will not fly out of your nose (or your arse).
Anything can happen.
Only fools think that a=a++; is a reasonable thing to write. I don't know what they thing it will accomplish. A more reasonable, but also sinister, situation is when a and a has different names and are pointers pointing at the same variable. On a supetscalar processor the instructions might then be
  move @a,@b
  add @a,@b,1
with both instructions executing at the same time. When both instructions retire and both attempt to update what a points to (@a) at the same time, the processor will detect this and raise some low level exception. If this happens in your nose transplant then nasal daemons is a reasonable result.

I too am with Bruce Holt. "a = a++;" is perfectly valid C code. It might be stupid code, but I expect that no C compiler will kill my dog because I run this code.

The only think in dispute is what it's outcome will be, as there is no implicit sequence to the "load", "store" and "increment" operations. The issue is that the compiler and CPU is free to schedule store and increment order it likes, and can change that order depending on a whim.

Likewise there is nothing wrong with this code:

Code: [Select]
   *p1 = (*p2)++;

but if p1 == p2, then the value pointed to be p1 then the program's memory may not change as I expect. My dog will still be safe.

All languages have undefined corners and rough edges, they are fun to peak into when bored, but I am sure we all agree  in general you stay away from them so your code works reliably, predictably and can be maintained.

Integer addition can lead to undefined behavior, as can subtraction, and multiplication, and division... you really don't have much left that is always guaranteed to never shoot yourself in the foot, regardless of language - you just have to know when you are in the "safe operating area" of the language.



Gaze not into the abyss, lest you become recognized as an abyss domain expert, and they expect you keep gazing into the damn thing.
 
The following users thanked this post: hans

Offline glarsson

  • Frequent Contributor
  • **
  • Posts: 814
  • Country: se
Re: An 'interesting' thing you can do in C++
« Reply #113 on: September 13, 2018, 08:55:02 am »
I too am with Bruce Holt. "a = a++;" is perfectly valid C code.
The 6800 microprocessor had a couple of undefined instructions. Using them invoked undefined behavior. For the earliest revisions of the 6800 one of the consequences of invoking undefined behavior was to enable two  buffers to drive the internal data bus at the same time. The practical consequence was that you had to buy a new 6800 — after the processor had short circuited itself to death.
 
The following users thanked this post: MK14

Online newbrain

  • Super Contributor
  • ***
  • Posts: 1719
  • Country: se
Re: An 'interesting' thing you can do in C++
« Reply #114 on: September 13, 2018, 09:00:17 am »
"a = a++;" is perfectly valid C code.
I sincerely hope my (and anyone else's) physical and financial health will never depend on your code.
Nandemo wa shiranai wa yo, shitteru koto dake.
 
The following users thanked this post: MK14

Online hans

  • Super Contributor
  • ***
  • Posts: 1639
  • Country: nl
Re: An 'interesting' thing you can do in C++
« Reply #115 on: September 13, 2018, 09:06:41 am »
No, that's not nasal demons. After "a=a++;", a will either have the same value as before, or will be incremented by 1. There are no other options. The program will not crash. Your computer will not catch on fire. Demons will not fly out of your nose (or your arse).
Anything can happen.
Only fools think that a=a++; is a reasonable thing to write. I don't know what they thing it will accomplish. A more reasonable, but also sinister, situation is when a and a has different names and are pointers pointing at the same variable. On a supetscalar processor the instructions might then be
  move @a,@b
  add @a,@b,1
with both instructions executing at the same time. When both instructions retire and both attempt to update what a points to (@a) at the same time, the processor will detect this and raise some low level exception. If this happens in your nose transplant then nasal daemons is a reasonable result.

https://en.wikipedia.org/wiki/Hazard_(computer_architecture)#Write_after_write_(WAW)

These hazards are common and it's the job of a CPU architecture engineer. Superscalar processors use register renaming to determine what register values are actually alive at which point, and is free to reorder instructions in order to do so. But aboveall, it will know that the value of 'a' will contain the addition of b+1 in your example, so any future references of 'a' must wait on the ADD instruction and not the MOV.

A compiler will need to output it's result in a sequential set of instructions. There is no concept of "at the same time" here. This is a trick done in hardware to speed up the average execution of typical processor programs.

If you argue that the compiler may arbitrarily choose the order of mov or add ; I think that's ill founded. I don't know of any construct in a programming language that allows you to run code outside of the scope of your function. You could model the ++ operator as a function like:
Code: [Select]
void postinc(int& a) {
  int t = a;
  a++;
  return t;
}
int main(int argc, char** args) {
  argc = postinc(argc);
  return argc;
}

I don't see any reason why a compiler would reorder any of these operations. This program will return the value of argc unmodified.
« Last Edit: September 13, 2018, 09:13:03 am by hans »
 

Offline GeorgeOfTheJungle

  • Super Contributor
  • ***
  • !
  • Posts: 2699
  • Country: tr
Re: An 'interesting' thing you can do in C++
« Reply #116 on: September 13, 2018, 09:07:00 am »
"a = a++;" is perfectly valid C code.
I sincerely hope my (and anyone else's) physical and financial health will never depend on your code.

It's even got a mnemonic: IncrementPerhaps INCPRHPS
« Last Edit: September 13, 2018, 09:09:15 am by GeorgeOfTheJungle »
The further a society drifts from truth, the more it will hate those who speak it.
 
The following users thanked this post: MK14

Online MK14

  • Super Contributor
  • ***
  • Posts: 4539
  • Country: gb
Re: An 'interesting' thing you can do in C++
« Reply #117 on: September 13, 2018, 09:17:52 am »
It's even got a mnemonic: IncrementPerhaps INCPRHPS

I think on some cpus, it is called MAYBEincA, and on some others it is called DOGkill, or MOTHERgreen.
There is this mysterious one, from China, with the NOSEdemon instruction, HEX code 666.
But I can't understand its develish description.
 

Offline hamster_nzTopic starter

  • Super Contributor
  • ***
  • Posts: 2803
  • Country: nz
Re: An 'interesting' thing you can do in C++
« Reply #118 on: September 13, 2018, 09:43:56 am »
"a = a++;" is perfectly valid C code.
I sincerely hope my (and anyone else's) physical and financial health will never depend on your code.

Um... Sorry, too late  :D. - but I ensured I compared the MD5 hash at both the data at source and destination, just to be sure.

"a = a++;" it is dumb code, stupid code, I hope I never see it in a program, and perhaps an unintentional random behavior generator depending on which way the wind blow, but it is valid C code, it will compile, and it will run.

Code: [Select]
$cat pp.c
#include <stdio.h>

int main(int argc, char *argv[])
{
   int a = 5;
   a = a++;
   switch(a) {
     case 5:
        printf("Option 1\n");
        break;
     case 6:
        printf("Option 2\n");
        break;
     default:
        printf("The world has ended\n");
        break;
   }
}
$gcc -o pp pp.c -pedantic -O4
$./pp
Option 1
$

Yes, I know that with -Wall it does generate a warning...
Gaze not into the abyss, lest you become recognized as an abyss domain expert, and they expect you keep gazing into the damn thing.
 

Offline hamster_nzTopic starter

  • Super Contributor
  • ***
  • Posts: 2803
  • Country: nz
Re: An 'interesting' thing you can do in C++
« Reply #119 on: September 13, 2018, 09:53:43 am »
No, that's not nasal demons. After "a=a++;", a will either have the same value as before, or will be incremented by 1. There are no other options. The program will not crash. Your computer will not catch on fire. Demons will not fly out of your nose (or your arse).
Anything can happen.
Only fools think that a=a++; is a reasonable thing to write. I don't know what they thing it will accomplish. A more reasonable, but also sinister, situation is when a and a has different names and are pointers pointing at the same variable. On a supetscalar processor the instructions might then be
  move @a,@b
  add @a,@b,1
with both instructions executing at the same time. When both instructions retire and both attempt to update what a points to (@a) at the same time, the processor will detect this and raise some low level exception. If this happens in your nose transplant then nasal daemons is a reasonable result.

https://en.wikipedia.org/wiki/Hazard_(computer_architecture)#Write_after_write_(WAW)

These hazards are common and it's the job of a CPU architecture engineer. Superscalar processors use register renaming to determine what register values are actually alive at which point, and is free to reorder instructions in order to do so. But aboveall, it will know that the value of 'a' will contain the addition of b+1 in your example, so any future references of 'a' must wait on the ADD instruction and not the MOV.

A compiler will need to output it's result in a sequential set of instructions. There is no concept of "at the same time" here. This is a trick done in hardware to speed up the average execution of typical processor programs.

If you argue that the compiler may arbitrarily choose the order of mov or add ; I think that's ill founded. I don't know of any construct in a programming language that allows you to run code outside of the scope of your function. You could model the ++ operator as a function like:
Code: [Select]
void postinc(int& a) {
  int t = a;
  a++;
  return t;
}
int main(int argc, char** args) {
  argc = postinc(argc);
  return argc;
}

I don't see any reason why a compiler would reorder any of these operations. This program will return the value of argc unmodified.

It is more that the compiler can chose what machine code to use, and they are not all guaranteed to have identical results - the end result may change depending on the compiler used, the compiler options used and the target architecture. For example, maybe the compiler decides to inline some code, and is then can optimize away the ++ operation....

Gaze not into the abyss, lest you become recognized as an abyss domain expert, and they expect you keep gazing into the damn thing.
 

Online hans

  • Super Contributor
  • ***
  • Posts: 1639
  • Country: nl
Re: An 'interesting' thing you can do in C++
« Reply #120 on: September 13, 2018, 10:24:46 am »
Well that's right. A common optimization step in write-after-write hazard is not carry out the first write at all. The first write is useless, as the result gets overwritten anyway without any intermediate use.

So the ++; operation is redundant and can be removed. This is a valid optimization step.
However erroneous behaviour occurs if the compiler or CPU decides to reorder these write instructions, as that will influence the functional behaviour of the program. This is not called undefined behaviour, but a serious bug.

Hence, if you test out every compiler on godbolt.org (or any other compiler explorer you've got) and turn on the optimizer, then I bet all of them will return the incoming value.
Most assembly outputs I've seen do not touch the incoming argument at all with an add instruction, e.g. on x86 all I get is:
Quote
main:                                   # @main
        mov     eax, edi
        ret

And also no warnings or errors, by the way, with -Werror -Wall turned on. Even if the program is written as:
Quote
int main(int argc, char** args) {
    int* p = &argc;
    *p = argc++;
    return argc;
}
 

Online newbrain

  • Super Contributor
  • ***
  • Posts: 1719
  • Country: se
Re: An 'interesting' thing you can do in C++
« Reply #121 on: September 13, 2018, 10:52:04 am »
This program will return the value of argc unmodified.
That program does not exhibit undefined behaviour, so I don't understand your point: you've just provided a possible, naïve, implementation. :-//
But, in general, a compiler is free to reorder operations as it likes (even across SPs, if no volatile object is involved), as long as the abstract machine shows the same behaviour it would have had before the reordering.
For UB, this last constraint is voided. :horse:

Quote
The result was that a block local variable would keep its random uninitialized value.

If a was uninitialized before that line, it would have to remain so after it, so that's ok, isn't it?
IIRC, it was along the lines of y[n] = z[n++], with 'y' a local array.
It was definitely not OK...

Nandemo wa shiranai wa yo, shitteru koto dake.
 

Offline dmills

  • Super Contributor
  • ***
  • Posts: 2093
  • Country: gb
Re: An 'interesting' thing you can do in C++
« Reply #122 on: September 13, 2018, 11:17:02 am »
That one is fairly classic, the other good one is that if you do a pointer null check after dereferencing the pointer the compiler is free to take the fact that you have dereferenced the pointer as guaranteeing that the pointer is non null.

x=p->foo;
if (p == NULL){...... // This block will be removed as dead code because the dereference above says that p cannot be null without involving UB.

Yes, the null check was in the wrong place, but the some of the security types still got sniffy when this behaviour was introduced.

Regards, Dan.

 
The following users thanked this post: newbrain

Online hans

  • Super Contributor
  • ***
  • Posts: 1639
  • Country: nl
Re: An 'interesting' thing you can do in C++
« Reply #123 on: September 13, 2018, 11:30:44 am »
This program will return the value of argc unmodified.
That program does not exhibit undefined behaviour, so I don't understand your point: you've just provided a possible, naïve, implementation. :-//
But, in general, a compiler is free to reorder operations as it likes (even across SPs, if no volatile object is involved), as long as the abstract machine shows the same behaviour it would have had before the reordering.
For UB, this last constraint is voided. :horse:

Quote
The result was that a block local variable would keep its random uninitialized value.

If a was uninitialized before that line, it would have to remain so after it, so that's ok, isn't it?
IIRC, it was along the lines of y[n] = z[n++], with 'y' a local array.
It was definitely not OK...

Because: https://en.cppreference.com/w/cpp/language/eval_order#Undefined_behavior_2

I'm bringing this point up because people seem not to understand what language specifications are.

I agree, UB happens in the circumstances that you describe. But in the example of "a=a++" that doesn't need to happen.
 

Offline glarsson

  • Frequent Contributor
  • **
  • Posts: 814
  • Country: se
Re: An 'interesting' thing you can do in C++
« Reply #124 on: September 13, 2018, 11:49:04 am »
So the ++; operation is redundant and can be removed. This is a valid optimization step.
Unless the variable is declared volatile, then "both" writes must happen.

But then again, if you invoke undefined behavior anything can happen.
 

Offline GeorgeOfTheJungle

  • Super Contributor
  • ***
  • !
  • Posts: 2699
  • Country: tr
Re: An 'interesting' thing you can do in C++
« Reply #125 on: September 13, 2018, 12:25:10 pm »
Quote
The result was that a block local variable would keep its random uninitialized value.
If a was uninitialized before that line, it would have to remain so after it, so that's ok, isn't it?
IIRC, it was along the lines of y[n] = z[n++], with 'y' a local array.
It was definitely not OK...

Ok, good, but then that's not the "a= a++;" we were talking about!
The further a society drifts from truth, the more it will hate those who speak it.
 

Offline GeorgeOfTheJungle

  • Super Contributor
  • ***
  • !
  • Posts: 2699
  • Country: tr
Re: An 'interesting' thing you can do in C++
« Reply #126 on: September 13, 2018, 12:29:56 pm »
"a = a++;" is perfectly valid C code.

Syntactically yes, but semantically it's... ambiguous.
« Last Edit: September 13, 2018, 12:43:27 pm by GeorgeOfTheJungle »
The further a society drifts from truth, the more it will hate those who speak it.
 

Offline macboy

  • Super Contributor
  • ***
  • Posts: 2254
  • Country: ca
Re: An 'interesting' thing you can do in C++
« Reply #127 on: September 13, 2018, 02:09:01 pm »
Why do you feel "break" is evil?

Totally beats me. That's what everybody were taught, on compulsory programming introduction courses (in C++), in the university I attended. (To be fair, we were actually taught that "break" is not as Evil as goto or ?:, but still a bit Evil.)

Of course, writing practical code in real life while completely avoiding ?: or break or even goto is nearly impossible, or at least detrimental to code quality and readability, as well as psychological productivity.

That said, now I remembered an additional detail: they had an exception that it is allowed to use break inside switch-case, but only there. They figured out switch-case doesn't work without it, and were not bold enough to claim switch-case is Evil.

This is all  :-DD , but at the same time, it's quite  :-- as well.

(Also note that creating such "order" of Evil-ity is ridiculous. In some contexts, goto results in much more readable result than break, yet it's down the list of things to be "frowned upon". It's always dependent on usage. But I guess we have no debate about this here.)
I have no qualms about using break (or even continue) but only in cases where it makes the program flow easier to construct and easier to read/understand. Yes there are such cases.  Especially when writing low level code as I do, there are times when you need to terminate a loop "early" due to some unforeseeable error and/or timing information from hardware.  My use of continue is much more rare, but there are occasions where it, too, just makes sense. I have literally never used a goto in C/C++, and never will. I cringe when I see one. On the other hand, when writing assembly code, program flow essentially all boils down to goto/branch statements, so that's that.

I restrict use of ?: to where it makes code cleaner. A prime example is where I check a flag and print a different substring based on it. e.g.:
Code: [Select]
printf("some operation state is %s\n", (someState == state_invalid_c)? "Invalid" : "OK");I like this better than printing the first part of the string, then doing a if/else to print one of the two different status strings.
 

Online RoGeorge

  • Super Contributor
  • ***
  • Posts: 6202
  • Country: ro
Re: An 'interesting' thing you can do in C++
« Reply #128 on: September 13, 2018, 02:33:49 pm »
Once I counted how many goto were in the Linux Kernel.  I don't remember the number, but there were A LOT of goto lines.

Offline GeorgeOfTheJungle

  • Super Contributor
  • ***
  • !
  • Posts: 2699
  • Country: tr
Re: An 'interesting' thing you can do in C++
« Reply #129 on: September 13, 2018, 02:39:57 pm »
There's a (name hidden) database for the Mac with a Pascal-like language that has no return nor break nor continue nor of course goto.
The further a society drifts from truth, the more it will hate those who speak it.
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3146
  • Country: ca
Re: An 'interesting' thing you can do in C++
« Reply #130 on: September 13, 2018, 03:00:46 pm »
That one is fairly classic, the other good one is that if you do a pointer null check after dereferencing the pointer the compiler is free to take the fact that you have dereferenced the pointer as guaranteeing that the pointer is non null.

x=p->foo;
if (p == NULL){...... // This block will be removed as dead code because the dereference above says that p cannot be null without involving UB.

Yes, the null check was in the wrong place, but the some of the security types still got sniffy when this behaviour was introduced.

Compilers are very good at optimizing horrible code because it's easy to do. And, over the years, they find newer and better ways to do this. Not so much with reasonably well-written code.
 

Offline Bassman59

  • Super Contributor
  • ***
  • Posts: 2501
  • Country: us
  • Yes, I do this for a living
Re: An 'interesting' thing you can do in C++
« Reply #131 on: September 13, 2018, 05:55:50 pm »
"a = a++;" is perfectly valid C code.

Syntactically yes, but semantically it's... ambiguous.

For what it's worth, Xcode (which uses LLVM) puts up a warning as soon as you type the line.

 
The following users thanked this post: MK14

Offline brucehoult

  • Super Contributor
  • ***
  • Posts: 4036
  • Country: nz
Re: An 'interesting' thing you can do in C++
« Reply #132 on: September 13, 2018, 09:37:58 pm »
Nope, I'm with brucehoult on this one, our mothers are safe.
I'm partially in total disagreement.
Our mothers might be safe, but hyperbole is a man's best friend.

Unfortunately I have lost the example (code, specific version of gcc and flags used) where a similar line was completely ignored by the compiler.
Skipped, no code emitted, no warning.
The result was that a block local variable would keep its random uninitialized value.

That's absolutely fair. If a has an undefined value then so does a++.
 

Online MK14

  • Super Contributor
  • ***
  • Posts: 4539
  • Country: gb
Re: An 'interesting' thing you can do in C++
« Reply #133 on: September 14, 2018, 04:39:28 pm »
Let's ask an extreme world class expert on compiler design (particularly C and C++), if UNDEFINED, can do ANYTHING, or if it is limited to one or two reasonable/obvious values ?

"Hello, Dr GCC, can you please answer this question for us" ?

Here is my program...

#include <stdio.h>

int i;

int main(void)
{
  i = 0;
  i *= (i *= ++i) * (i *= i) * (i *= i) * (i *= i) * (i *= ++i);
  printf("\nDemo1 = i = %d\n", i);

  i = 0;
  i *= (i *= ++i) * (i *= i) * (i *= ++i) * (i *= i) * (i *= ++i);
  printf("\nDemo2 = i = %d\n", i);
}

"So, Dr GCC, what is the answer" ?

gcc eevblog.c -oeevblog
./eevblog
"No flags were changed from default, and no errors or warnings came up"

Demo1 = i = 0

Demo2 = i = -1554387584

"Thanks, DR GCC".

tl;dr
Going from 0, to -1554387584, because of one extra ++, in the middle of an expression (disappointingly, GCC (very recent version) gave no warnings or errors). Seems to me (and Dr GCC), that ANYTHING, can happen, when you use UNDEFINED things in your programs.

Now, to really prove a point. Let's do it again, and just tidy up the code. The results will be the same, surely ?

#include <stdio.h>
int main(void)
{
  int i = 0;
  i *= (i *= ++i) * (i *= i) * (i *= i) * (i *= i) * (i *= ++i);
  printf("Demo1 = i = %d\n", i);
  i = 0;
  i *= (i *= ++i) * (i *= i) * (i *= ++i) * (i *= i) * (i *= ++i);
  printf("Demo2 = i = %d\n", i);
}

gcc eevblog.c -oeevblog
./eevblog
                               ..."Again, no errors or warnings"
Demo1 = i = 0
Demo2 = i = -368195456

So ANYTHING has changed its mind, again. Just because the variable was moved from globals to locals (presumably).
« Last Edit: September 14, 2018, 04:43:34 pm by MK14 »
 

Offline GeorgeOfTheJungle

  • Super Contributor
  • ***
  • !
  • Posts: 2699
  • Country: tr
Re: An 'interesting' thing you can do in C++
« Reply #134 on: September 14, 2018, 05:01:39 pm »
Use -Wsequence-point

kk.c: In function ‘main’:
kk.c:6: warning: operation on ‘i’ may be undefined
kk.c:9: warning: operation on ‘i’ may be undefined
The further a society drifts from truth, the more it will hate those who speak it.
 
The following users thanked this post: MK14

Online MK14

  • Super Contributor
  • ***
  • Posts: 4539
  • Country: gb
Re: An 'interesting' thing you can do in C++
« Reply #135 on: September 14, 2018, 05:07:42 pm »
Use -Wsequence-point

kk.c: In function ‘main’:
kk.c:6: warning: operation on ‘i’ may be undefined
kk.c:9: warning: operation on ‘i’ may be undefined

Originally, I was using -Wall and had the optimiser on (-O3), which also produced the warnings and the same results, at least for the first program.
But I removed any unnecessary clutter, to reduce the size of the demo program, for the forum post.
 

Online MK14

  • Super Contributor
  • ***
  • Posts: 4539
  • Country: gb
Re: An 'interesting' thing you can do in C++
« Reply #136 on: September 14, 2018, 08:15:06 pm »
The code for the second program is typed in and ready for anyone to try or change (press FORK-THIS), online, here:
https://onlinegdb.com/HyBUB9KuQ

Code: [Select]
#include <stdio.h>
int main()
{
  int i = 0;
  i *= (i *= ++i) * (i *= i) * (i *= i) * (i *= i) * (i *= ++i);
  printf("Demo1 = i = %d\n", i);
  i = 0;
  i *= (i *= ++i) * (i *= i) * (i *= ++i) * (i *= i) * (i *= ++i);
  printf("Demo2 = i = %d\n", i);
}

Results:
Code: [Select]
Demo1 = i = 0                                                                                                                 
Demo2 = i = -368195456                                                                                                         
...Program finished with exit code 0                                                                                           
Press ENTER to exit console

« Last Edit: September 14, 2018, 08:24:58 pm by MK14 »
 

Online MK14

  • Super Contributor
  • ***
  • Posts: 4539
  • Country: gb
Re: An 'interesting' thing you can do in C++
« Reply #137 on: September 14, 2018, 08:49:54 pm »
If you change the variable type to double, and initial value to pi. Done here:
https://onlinegdb.com/ryiQCqY_Q]
It goes even crazier.
Demo1 = i = 84465015249278344875802672090097198053720064.000000                                                     
Demo2 = i = 446308403328.000000

Demo1, rapidly increases if you increase the initial value, yet demo2 remains apparently constant.
Weird, really weird.
« Last Edit: September 14, 2018, 08:51:41 pm by MK14 »
 

Offline brucehoult

  • Super Contributor
  • ***
  • Posts: 4036
  • Country: nz
Re: An 'interesting' thing you can do in C++
« Reply #138 on: September 14, 2018, 10:17:48 pm »
Let's ask an extreme world class expert on compiler design (particularly C and C++), if UNDEFINED, can do ANYTHING, or if it is limited to one or two reasonable/obvious values ?

You put 12 (or 13) arithmetic operations between your sequence points, with 2 (or 3) of those operations having side-effects. The compiler is limited to doing those operations, in some order.

The result is going to be some number.

The result is *not* going to be your computer catching on fire.
 
The following users thanked this post: hans, MK14

Offline brucehoult

  • Super Contributor
  • ***
  • Posts: 4036
  • Country: nz
Re: An 'interesting' thing you can do in C++
« Reply #139 on: September 14, 2018, 10:29:18 pm »
If you change the variable type to double, and initial value to pi. Done here:
https://onlinegdb.com/ryiQCqY_Q]
It goes even crazier.
Demo1 = i = 84465015249278344875802672090097198053720064.000000                                                     
Demo2 = i = 446308403328.000000

Demo1, rapidly increases if you increase the initial value, yet demo2 remains apparently constant.
Weird, really weird.

446308403328 is 2^7 * 3^20.  446308403328 % 2^32 - 2^32 = -368195456

Nothing strange here, it's just the result of incrementing 0 twice and three times and doing a little multiplying and squaring -- exactly as you told it to. And then truncating the answer to a 32 bit signed integer.
 
The following users thanked this post: MK14

Online MK14

  • Super Contributor
  • ***
  • Posts: 4539
  • Country: gb
Re: An 'interesting' thing you can do in C++
« Reply #140 on: September 14, 2018, 10:30:56 pm »
The result is *not* going to be your computer catching on fire.

It depends on the computer hardware, and what it is connected to.
If it is an autonomous self-driving car, driving at high speed on a motorway.
Then it could cause an accident, which results in the vehicle (and hence the computer), catching on fire.

But I agree, in general, in most cases, serious software bugs, will not (usually) set the computer on fire.
 

Online MK14

  • Super Contributor
  • ***
  • Posts: 4539
  • Country: gb
Re: An 'interesting' thing you can do in C++
« Reply #141 on: September 14, 2018, 10:40:58 pm »
446308403328 is 2^7 * 3^20.  446308403328 % 2^32 - 2^32 = -368195456

Nothing strange here, it's just the result of incrementing 0 twice and three times and doing a little multiplying and squaring -- exactly as you told it to. And then truncating the answer to a 32 bit signed integer.

Thanks for giving that insight. I did not realise, that is what it was doing.
But I still believe that since it is "undefined", it should NOT be used in normal/real coding practice.

Also, if you change the language (but keep the source code the same), via those online links I posted. Those numbers, change quite a lot, between C and C++, language selections!

Since i starts out as 0 (in earlier programs), and it is basically i *= ... lots of stuff ***
It possibly should be evaluating to 0 (basic maths 0 x stuff = 0).
But I am NOT familiar enough with the full C and C++ language specifications, to know how it is suppose to handle that situation.
Presumably, because -Wall, says UNDEFINED. It is undefined, and can be anything it likes.

EDIT: Original(C): https://onlinegdb.com/HyBUB9KuQ
Demo1 = i = 0                                                                                                       
Demo2 = i = -368195456
...Switching language  to C++ https://onlinegdb.com/Sy1pRhYOX , source code kept same.
...Results now have changed to (via C to C++ language switch) ...
Demo1 = i = 16                                                                                                                 
Demo2 = i = 5345344

In my perception (ignoring UNDEFINED means ANYTHING can happen),
going from C to C++ (source code kept IDENTICAL), should not really change the output values.
But I guess some of the changes between C and C++, have caused this, so it is not unreasonable, just a bit weird.
« Last Edit: September 14, 2018, 11:08:59 pm by MK14 »
 

Offline brucehoult

  • Super Contributor
  • ***
  • Posts: 4036
  • Country: nz
Re: An 'interesting' thing you can do in C++
« Reply #142 on: September 14, 2018, 11:09:31 pm »
The code for the second program is typed in and ready for anyone to try or change (press FORK-THIS), online, here:
https://onlinegdb.com/HyBUB9KuQ

Code: [Select]
#include <stdio.h>
int main()
{
  int i = 0;
  i *= (i *= ++i) * (i *= i) * (i *= i) * (i *= i) * (i *= ++i);
  printf("Demo1 = i = %d\n", i);
  i = 0;
  i *= (i *= ++i) * (i *= i) * (i *= ++i) * (i *= i) * (i *= ++i);
  printf("Demo2 = i = %d\n", i);
}

Results:
Code: [Select]
Demo1 = i = 0                                                                                                                 
Demo2 = i = -368195456                                                                                                         
...Program finished with exit code 0                                                                                           
Press ENTER to exit console

I get exactly the same result with gcc for any of i386, RISC-V or ARM.

I get exactly the same result with -O0 (in which case the arithmetic is done at runtime, in main) or with -O1 (in which case the arithmetic is done by the compiler and the answer is simply printed.

Here is the RISC-V code for -O0. The others are the exact equivalent. They just keep some temporary values in registers and save and load values of i to its stack slot in memory.

Code: [Select]
# i=0
sw      zero,-20(s0)

lw      a5,-20(s0)
addi    a5,a5,1
sw      a5,-20(s0)
lw      a3,-20(s0)
lw      a5,-20(s0)
addi    a5,a5,1
sw      a5,-20(s0)
lw      a4,-20(s0)
lw      a5,-20(s0)
addi    a5,a5,1
sw      a5,-20(s0)
lw      a5,-20(s0)
lw      a2,-20(s0)
mul     a3,a2,a3
sw      a3,-20(s0)
lw      a2,-20(s0)
lw      a3,-20(s0)
mul     a3,a2,a3
sw      a3,-20(s0)
lw      a2,-20(s0)
lw      a3,-20(s0)
mul     a3,a2,a3
lw      a2,-20(s0)
mul     a4,a2,a4
sw      a4,-20(s0)
lw      a4,-20(s0)
mul     a3,a3,a4
lw      a2,-20(s0)
lw      a4,-20(s0)
mul     a4,a2,a4
sw      a4,-20(s0)
lw      a4,-20(s0)
mul     a4,a3,a4
lw      a3,-20(s0)
mul     a5,a3,a5
sw      a5,-20(s0)
lw      a5,-20(s0)
mul     a5,a4,a5
lw      a4,-20(s0)
mul     a5,a4,a5
sw      a5,-20(s0)

#print
lw      a1,-20(s0)
lui     a5,0x1b
addi    a0,a5,2016 # 1b7e0 <__clzsi2+0x4a>
jal     1044e <printf>

Clang gives a different answer to gcc (5345344 = 2^6 * (2^4 + 1)^4) , but it gives the same answer across different CPU types and different optimisation levels, and again does the actual calculation in machine code with -O0 but just prints the final answer directly with -O1.

While you might not find the answer easy to predict, it seems there really are only a couple of likely answers. Certainly no explosions.
 
The following users thanked this post: MK14

Online MK14

  • Super Contributor
  • ***
  • Posts: 4539
  • Country: gb
Re: An 'interesting' thing you can do in C++
« Reply #143 on: September 14, 2018, 11:16:45 pm »
Wow, that's an amazing piece of work you have just done.

I can now better understand, your point of view.

C/C++ source code, changing its behaviour, between GCC, CLANG and presumably other compilers. Would still cause all sorts of practical difficulties, and the immense difficulty in predicting what the code really does (how it gets to the answers), would make it a nightmare or at least difficult/tricky to change in the future.

But having primarily two different values, is not impossible to handle.
E.g. Conditional Compiling and/or early tests in the source code to see which way round such things will be handled by the compiler.

A bit like, C/C++, is a bit weak as regards if the integer default is 32 or 64 bits.
So, some clever source code systems, do some checks early on and set things up, so it can handle the various possibilities.

Just to be clear. I still think UNDEFINED is a bad idea to code with, and can still potentially cause at least two different outcomes. Presumably it still can be ANYTHING, but you have presented some nice arguments as to why it may be often less than anything.
« Last Edit: September 14, 2018, 11:21:31 pm by MK14 »
 

Offline brucehoult

  • Super Contributor
  • ***
  • Posts: 4036
  • Country: nz
Re: An 'interesting' thing you can do in C++
« Reply #144 on: September 15, 2018, 12:32:28 am »
Wow, that's an amazing piece of work you have just done.

I can now better understand, your point of view.

C/C++ source code, changing its behaviour, between GCC, CLANG and presumably other compilers. Would still cause all sorts of practical difficulties, and the immense difficulty in predicting what the code really does (how it gets to the answers), would make it a nightmare or at least difficult/tricky to change in the future.

It's a VERY VERY bad idea to write code like that. It's bad programming.

But you wrote three of ++i and there are three of "addi x,y,1" in the generated code.
You wrote ten of "*" or "*=" and there are ten "mul" in the generated code.

All that changes is the order of those thirteen operations and which results are saved and used again later, and when.

I don't know how many reasonable answers there are. It's probably dozens or hundreds. But the answer is a number, not an explosion.

I've shown that if you use the same compiler (and compiler version) across different CPU types you'll get the same answer. Different compilers can produce different answers, but there are't a lot of different compilers in use these days.

Different versions of the same compiler *could* produce different answers, but this will be less common. The gcc versions I used were 7.3.0 for i386 and ARM, and 7.2.0 for RISC-V. I just tried another x86 machine with gcc 5.4.0 and got the same answer (and the same for both i386 and x86_64)

As you showed, you also get the same answer for int and for double precision FP, once you take into account the range limitations of int. The same operations are done in the same order.

But anyway DON'T CODE LIKE THIS!! Don't use ++ or -- on a variable if that variable appears more than once in the statement (right AND left sides).
 
The following users thanked this post: hans, MK14

Offline brucehoult

  • Super Contributor
  • ***
  • Posts: 4036
  • Country: nz
Re: An 'interesting' thing you can do in C++
« Reply #145 on: September 15, 2018, 12:49:01 am »
EDIT: Original(C): https://onlinegdb.com/HyBUB9KuQ
Demo1 = i = 0                                                                                                       
Demo2 = i = -368195456
...Switching language  to C++ https://onlinegdb.com/Sy1pRhYOX , source code kept same.
...Results now have changed to (via C to C++ language switch) ...
Demo1 = i = 16                                                                                                                 
Demo2 = i = 5345344

16 and 5345344 are the same answers clang gets for both C and C++, for all CPU types I tried. It's an interesting question why gcc and g++ would get different answers.
 
The following users thanked this post: MK14

Online MK14

  • Super Contributor
  • ***
  • Posts: 4539
  • Country: gb
Re: An 'interesting' thing you can do in C++
« Reply #146 on: September 15, 2018, 02:06:44 am »
16 and 5345344 are the same answers clang gets for both C and C++, for all CPU types I tried. It's an interesting question why gcc and g++ would get different answers.

Another AMAZING change of value (which the concept is very likely to be how you described, where it is changes in order of the calculations, has a big impact on the final answers), is when you leave the source code unchanged.
Except for where the integer variable i, is declared. Between before main(), and declaring it within the main() {} codeblocks.

When it is before main(), the value changes to (as detailed in a much earlier post of mine, in this thread):
Demo1 = i = 0
Demo2 = i = -1554387584

EDIT: Unable to reproduce these strange values, using the online compiler, as it comes up with the same values as before. But I can still reproduce these values by using my local Linux machines GCC version:
Code: [Select]
gcc --version
gcc (Ubuntu 7.3.0-16ubuntu3) 7.3.0
So it is probably because the online version uses strange memory models,
or my local GCC has bug(s), applicable to this issue or some other explanation.
End of EDIT.

I'm amazed, that just changing where/how an integer is declared, changes its calculated value, like that.

Usually, such a change in allocation, would be invisible to the C/C++ code. Unless other C/C++ files attempt to access the variable and/or its operations are timed extremely carefully. I've seen slight (tiny) timing variations, because it is on the stack, heap, somewhere in memory or in registers, depending on the compiler, cpu, implementation, optimisation level, etc.

Maybe it is a "race hazard", between different initialisation sections of the C/C++ code, or other peculiarities ?
But there are many other possible explanations.

If I get the inclination, I may spend time, and try and find out why this happens.
« Last Edit: September 15, 2018, 02:35:06 am by MK14 »
 

Offline westfw

  • Super Contributor
  • ***
  • Posts: 4199
  • Country: us
Re: An 'interesting' thing you can do in C++
« Reply #147 on: September 15, 2018, 03:32:32 am »
I've noticed an annoying trend.
In the old days, if you used an ambiguous syntax that the spec claimed was "undefined", you would tend to get a result that made sense, more or less.  It might not be the same on all systems and all compilers, but each result would be ... sensible, looked at from some perspective.
More recently, less so.  The compiler developers mumble about optimization and etc, but I think they're doing it out of spite.
Some of the cases are particularly annoying to embedded developers.I've run into situation where common constructs no longer work as expected:
Code: [Select]
uint8_t time = 0 - delaytime;while (++time != 0) {    //stuff.}"The behavior of C WRT integer overflow is undefined.  The compiler decided that incrementing a non-zero value would never reach 0, and made the loop unconditional and infinite."

Code: [Select]
   while (1);   // stop the program"A while loop may be assumed to terminate.  Since the loop is empty and doesn't do anything, the code was entirely omitted."
https://stackoverflow.com/questions/16436237/is-while1-undefined-behavior-in-c

Grr.
 
The following users thanked this post: oPossum, MK14

Online newbrain

  • Super Contributor
  • ***
  • Posts: 1719
  • Country: se
Re: An 'interesting' thing you can do in C++
« Reply #148 on: September 15, 2018, 11:49:30 am »
I've noticed an annoying trend.
In the old days, if you used an ambiguous syntax that the spec claimed was "undefined", you would tend to get a result that made sense, more or less.  It might not be the same on all systems and all compilers, but each result would be ... sensible, looked at from some perspective.
More recently, less so.  The compiler developers mumble about optimization and etc, but I think they're doing it out of spite.
Some of the cases are particularly annoying to embedded developers.I've run into situation where common constructs no longer work as expected:
Code: [Select]
uint8_t time = 0 - delaytime;while (++time != 0) {    //stuff.}"The behavior of C WRT integer overflow is undefined.  The compiler decided that incrementing a non-zero value would never reach 0, and made the loop unconditional and infinite."

Code: [Select]
   while (1);   // stop the program"A while loop may be assumed to terminate.  Since the loop is empty and doesn't do anything, the code was entirely omitted."
https://stackoverflow.com/questions/16436237/is-while1-undefined-behavior-in-c

Grr.
I'm a bit puzzled by both of these statements:
  • The behaviour of overflow in unsigned integral types is actually well defined (that's the major point for using them, IMO), optimising that away it's simply wrong.
    If someone uses a signed integer there, it's their fault.
  • while(1) does not fall in the 6.8.5/6 clause added in C11, so it has defined (and expected) behaviour.
    That clause refers to loops where the controlling expression is not a constant expression (and etc. etc.)*.
    One of the good reason to use a volatile object.
    But, yes, an earlier version was more problematic.

If they are doing that out of spite for the use of well known undefined constructs, I'm with them.
Better fail in a more visible way rather than instilling a misleading sense of confidence on behaviour that is not guaranteed in any way.
I actually would make your sound card go , and declare that a diagnostic (not that one is needed with UB).

And now is the time for the dreaded, misleading and easily rebuttable car analogy:
Using UB is like driving on the highway in the wrong direction. You might survive it, but it's something you should strive to avoid.

* Note: I only have access to the final draft of C11 (n1570), not the actual standard. That draft was approved without remarks, AFAIK.
« Last Edit: September 15, 2018, 12:01:28 pm by newbrain »
Nandemo wa shiranai wa yo, shitteru koto dake.
 
The following users thanked this post: MK14

Offline GeorgeOfTheJungle

  • Super Contributor
  • ***
  • !
  • Posts: 2699
  • Country: tr
Re: An 'interesting' thing you can do in C++
« Reply #149 on: September 15, 2018, 02:40:57 pm »
Code: [Select]
#include <stdio.h>
int main()
{
  int i = 0;
  i *= (i *= ++i) * (i *= i) * (i *= i) * (i *= i) * (i *= ++i);
  printf("Demo1 = i = %d\n", i);
  i = 0;
  i *= (i *= ++i) * (i *= i) * (i *= ++i) * (i *= i) * (i *= ++i);
  printf("Demo2 = i = %d\n", i);
}

I've tried out of curiosity and using int* i= malloc(sizeof(int)); and *i everywhere instead of i, it always gives 0 no matter what, with gcc in Intel and ARM.
The further a society drifts from truth, the more it will hate those who speak it.
 
The following users thanked this post: MK14

Online MK14

  • Super Contributor
  • ***
  • Posts: 4539
  • Country: gb
Re: An 'interesting' thing you can do in C++
« Reply #150 on: September 16, 2018, 12:11:41 am »
I've tried out of curiosity and using int* i= malloc(sizeof(int)); and *i everywhere instead of i, it always gives 0 no matter what, with gcc in Intel and ARM.

I tried it (Malloc and * etc, I changed the syntax a bit, so it supports C and C++) using the online GCC, and it came up with the same values as before (i.e. made no difference). But I'm not sure if the online GCC, uses strange memory models (i.e. they hacked/changed it, or it doesn't use the stack/heap system, etc etc), so that it can run using little/limited server resources.
So doing it on a real machine (I can well believe), could give different results.
The problem if I do it on my machine, is I can't directly share the results on the forum, for others to mess/experiment with it. Because we are probably running different OS versions, different GCC's etc.

https://onlinegdb.com/SJz0RMjO7
« Last Edit: September 16, 2018, 12:18:34 am by MK14 »
 

Offline brucehoult

  • Super Contributor
  • ***
  • Posts: 4036
  • Country: nz
Re: An 'interesting' thing you can do in C++
« Reply #151 on: September 19, 2018, 11:44:09 pm »
I've noticed an annoying trend.
In the old days, if you used an ambiguous syntax that the spec claimed was "undefined", you would tend to get a result that made sense, more or less.  It might not be the same on all systems and all compilers, but each result would be ... sensible, looked at from some perspective.
More recently, less so.  The compiler developers mumble about optimization and etc, but I think they're doing it out of spite.
Some of the cases are particularly annoying to embedded developers.I've run into situation where common constructs no longer work as expected:
Code: [Select]
uint8_t time = 0 - delaytime;while (++time != 0) {    //stuff.}"The behavior of C WRT integer overflow is undefined.  The compiler decided that incrementing a non-zero value would never reach 0, and made the loop unconditional and infinite."

Code: [Select]
   while (1);   // stop the program"A while loop may be assumed to terminate.  Since the loop is empty and doesn't do anything, the code was entirely omitted."
https://stackoverflow.com/questions/16436237/is-while1-undefined-behavior-in-c

Grr.

Those are pretty rubbish ways to do things, especially assuming processor speed (MHz and IPC) to get a delay. Much better to use a cycle count register. Alas some simpler MCUs don't have one. RISC-V *requires* all implementations to have a 32 bit cycle counter.

However, if you insist on coding that way, popping a 'asm volatile ("")' inside your loop will convince gcc at least to never optimise it away.
 

Online newbrain

  • Super Contributor
  • ***
  • Posts: 1719
  • Country: se
Re: An 'interesting' thing you can do in C++
« Reply #152 on: September 20, 2018, 07:51:47 am »
However, if you insist on coding that way, popping a 'asm volatile ("")' inside your loop will convince gcc at least to never optimise it away.
But do gcc or other compilers really optimise this things away?
In my reading of the standard this would definitely be non-conforming, have I overlooked something?

In the first case, if there are actually no statements with side effects inside the while ( "// stuff" ), the compiler could just assign 0 to delay and be done with that (since it's not been declared volatile), but cannot simply omit the loop, as its controlling expression has a visible side effect.

The second case is a bit hairier, but still it's not UB, and as such should be honoured. The compiler cannot assume it terminates and remove it as it has no side effects.
Nandemo wa shiranai wa yo, shitteru koto dake.
 

Online SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14472
  • Country: fr
Re: An 'interesting' thing you can do in C++
« Reply #153 on: September 20, 2018, 01:31:11 pm »
The second case is a bit hairier, but still it's not UB, and as such should be honoured. The compiler cannot assume it terminates and remove it as it has no side effects.

An infinite loop such as
Code: [Select]
while (1) ; should obviously not be optimized away as it has a clear an unambiguous effect: halting the execution.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf