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 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.
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
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.
Code: [Select](argc == 2 ? a : b) += 5;
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.
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.
I'd add that maybe C is like a 70's to 80's Toyota Corolla.
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.
Nope, I'm with brucehoult on this one, our mothers are safe.
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).
Only fools think that a=a++; is a reasonable thing to write.
I'm partially in total disagreement.
The result was that a block local variable would keep its random uninitialized value.
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.
*p1 = (*p2)++;
I too am with Bruce Holt. "a = a++;" is perfectly valid C code.
"a = a++;" is perfectly valid C code.
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.
void postinc(int& a) {
int t = a;
a++;
return t;
}
int main(int argc, char** args) {
argc = postinc(argc);
return argc;
}
"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
"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.
$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
$
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.
main: # @main
mov eax, edi
ret
int main(int argc, char** args) {
int* p = &argc;
*p = argc++;
return argc;
}
This program will return the value of argc unmodified.
QuoteThe 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?
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.QuoteThe 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...
So the ++; operation is redundant and can be removed. This is a valid optimization step.