Reputation: 7834
I heard about compiler optimizations.
For example the one when:
while(myBool)
doStuff();
compiler knows you do not modify myBool inside a while loop, it just read myBool once and doesn't check it every time.
This can be affected by volatile
keyword right?
So I have tried to "trick" compiler, it thinks value was not changed.
int main()
{
struct st
{
int a;
int b; //I want to make difference by writing volatile here
}s;
s.b = 1;
while(s.b > 0)
{
*((&s.a)+1) = 0;
std::cout << "test" << std::endl;
}
}
But even with full optimizations turned on (vs2012), this does not trick the compiler. This is probably very lame trick :)
How can I trick it? Is it even possible?
My goal is to create simple single-threaded program, which prints "test" with volatile
keyword used and prints infinite-times "test" without the keyword.
EDIT: Unfortunately I am not good with assembler, so I really can not read if the memory reading was optimized out in the first place :)
Upvotes: 2
Views: 435
Reputation: 4633
The short answer is that structs
are not guarenteed to be contiguous in memory. Arrays are. You can not access the struct like that!
A SO question that may be of help: Pointer arithmetic for structs. It goes into a little more detail about how you can not do this and why. But a summary is that there may or may not be padding between the fields of the struct. I particularly like Charlie's answer on that question.
Upvotes: 0
Reputation: 400562
What you're doing is undefined behavior. You can't access s.b
by writing to *((&s.a)+1)
instead since there's no guarantee that s.a
and s.b
don't have any padding bytes between them.
If you want to force there to be no padding, look into your compiler options. For GCC/Clang, you'd declare the structure with __attribute__((packed))
. For MSVC, you'd use the #pragma pack
directive.
There's no good reason to be accessing s.b
through s.a
using that code. What you should really do in this case, assuming you have a good reason for not accessing s.b
directly, is use an array (volatile
, if need be). Arrays are guaranteed to be contiguous in memory without needing special attributes/pragmas.
Furthermore, the compiler won't make certain optimizations in some cases: if i
is a variable and you write to a[i]
followed by a read of a[1]
, the compiler can't assume that a[1]
wasn't just written to, so it won't be able to cache it in a register. Whereas if you have two unrelated variables a
and b
and you write to *(&a+1)
and then read from b
, the compiler will assume that b
was not just written to. That's one very good reason why *(&a+1)
is undefined behavior, since it leads the compiler to make untrue assumptions and cause your program to behave in strange ways.
Upvotes: 2
Reputation: 3355
I think you are asking how to make sure that the compiler assumes the value is almost the same (in your example true) so the compliler optimizes for this value. If you do then your are looking for a compiler specific set of keywords. This is what I use in g++
#define predict_true__(exp) __builtin_expect((exp), 1)
#define predict_true__(exp) (exp)
This way you can do
while ( predict_true__( myBool ))
doStuff() ;
It will be running efficiently for myBool is true. Hope it helps and you will know what to look in case of visual you use.
Addition: I have found the following post which talks about it. I am afraid it is a sad talk, though: likely/unlikely equivalent for MSVC
Upvotes: 1