C Board  

Go Back   C Board > General Programming Boards > C Programming

Reply
 
LinkBack Thread Tools Display Modes
Old 01-07-2009, 12:19 AM   #1
Registered User
 
Join Date: Jan 2009
Posts: 7
Problem with compiling code with option -O2

Hello, everyone. I have met a problem when I was trying compiling the next code.

Code:
#include <stdio.h>

typedef union {
    short s[2];
    int i[1];
}foo;

int main()
{

    foo f;
    short *a = f.s;
    int   cnt = 0x22222222;;

    f.s[0]=0x1111;
    f.s[1]=0x1111;

    printf("%x %x\n", a[0], a[1]);
    printf("%x %x\n", f.s[0], f.s[1]);
    printf("\n");

    *f.i = cnt;

    printf("%x %x\n", a[0], a[1]);
    printf("%x %x\n", f.s[0], f.s[1]);
    printf("\n");


    printf("%x %x\n", a[0], a[1]);
    printf("%x %x\n", f.s[0], f.s[1]);
    printf("\n");

    return 0;
}
The compiler is gcc 3.2.3. When I used options -O. I got the result which I expected:
1111 1111
1111 1111

2222 2222
2222 2222

2222 2222
2222 2222

But when I used options -O2, I got the next result:
1111 1111
1111 1111

1111 1111
2222 2222

2222 2222
2222 2222

Could you explain where is the problem in the code?
Thanks for your help.
koushikyou is offline   Reply With Quote
Old 01-07-2009, 12:39 AM   #2
Beginner
 
leiming's Avatar
 
Join Date: Jan 2008
Location: Fujian, China
Posts: 23
1111 1111
1111 1111

2222 1111
2222 2222

2222 2222
2222 2222

Gcc 3.4.5 if -O2 is turned on
leiming is offline   Reply With Quote
Old 01-07-2009, 01:33 AM   #3
Beginner
 
leiming's Avatar
 
Join Date: Jan 2008
Location: Fujian, China
Posts: 23
I have come up with an idea,
is it because that a is only a pointer to 2 bytes so the compiler doesn't think it has effect beyond the 2 bytes to assign a value to pointer a
leiming is offline   Reply With Quote
Old 01-07-2009, 02:15 AM   #4
Registered User
 
Join Date: Apr 2006
Posts: 1,309
Looks like the compiler deduces that "*f.i = cnt;" and "a[0], a[1]" cannot access the same memory location, so it does puts a[0] and a[1] on the stack (in order to pass it to printf) prior or at the same time as modifying "*f.i". This is technically allowed, because accessing the member of a union as a short after assigning to the int version to is undefined behavior.

I surprised the compiler makes such a determination, however.
__________________
It is too clear and so it is hard to see.
A dunce once searched for fire with a lighted lantern.
Had he known what fire was,
He could have cooked his rice much sooner.
King Mir is offline   Reply With Quote
Old 01-07-2009, 02:20 AM   #5
Registered User
 
Join Date: Apr 2008
Posts: 282
compiling with -fno-strict-aliasing -O2 produces the correct result (or so it seems).

The wrong part is to declare i as a pointer (or an array, nevermind), because the compiler assumes it is not an alias to s, replacing int i[1]; by int i; in the union, and *f.i=0x2..2 by f.i=0x2..2 produces the correct result with -O2 and no additional option (because the compiler knows s and i are related).

Last edited by root4; 01-07-2009 at 02:32 AM.
root4 is offline   Reply With Quote
Old 01-07-2009, 02:36 AM   #6
Registered User
 
Join Date: Jan 2009
Posts: 7
Thank you for your comment.
Actually, this sample is modified from the next code:
Code:
#include <stdio.h>

int main()
{

  volatile short a[2];
  int   cnt = 0x22222222;

      a[0]=0x1111;
      a[1]=0x1111;

      printf("%x %x\n", a[0], a[1]);

      *(int *)a = (int)cnt; /* violation of aliasing rules */

      printf("%x %x\n", a[0], a[1]);

      printf("%x %x\n", a[0], a[1]);

  return 0;
}
According the information from google, I have known the line *(int *)a = (int)cnt; violate the aliasing rules. So I tried to fix this using union. But it seems not work. I want to figure out where the problem is and how to avoid it.
Some information from google may be helpful.
https://www.securecoding.cert.org/co...ompatible+type

Any helpful comment is welcome.
koushikyou is offline   Reply With Quote
Old 01-07-2009, 02:51 AM   #7
Registered User
 
Join Date: Apr 2008
Posts: 282
The page you linked provide a solution (the one you tried in your first post, except member i is not an array) and it works. Your last problem occurs when casting a pointer to a (non-compatible) type (an array of 2 shorts in not necessarily equivalent to an int, it depends on the implementation type size [the standard only says an int and a short have to be at least 16 bits long]). Plus in your case, indianness may also be an issue.
root4 is offline   Reply With Quote
Old 01-07-2009, 03:19 AM   #8
Registered User
 
Join Date: Jan 2009
Posts: 7
Thank you for your comment.
But I want to ask some further question.

Quote:
Originally Posted by root4 View Post
The wrong part is to declare i as a pointer (or an array, nevermind), because the compiler assumes it is not an alias to s, replacing int i[1]; by int i; in the union, and *f.i=0x2..2 by f.i=0x2..2 produces the correct result with -O2 and no additional option (because the compiler knows s and i are related).
In an union, how compiler determines one member is an alias to others or not? Is there any rule?
koushikyou is offline   Reply With Quote
Old 01-07-2009, 03:21 AM   #9
Kernel hacker
 
Join Date: Jul 2007
Location: Farncombe, Surrey, England
Posts: 15,686
Quote:
Originally Posted by koushikyou View Post
Thank you for your comment.
But I want to ask some further question.



In an union, how compiler determines one member is an alias to others or not? Is there any rule?
I expect it ALWAYS assumes members are aliased - since storing different forms of data aliased is the exact purpose of unions.

--
Mats
__________________
Compilers can produce warnings - make the compiler programmers happy: Use them!
Please don't PM me for help - and no, I don't do help over instant messengers.
matsp is offline   Reply With Quote
Old 01-07-2009, 03:27 AM   #10
Registered User
 
Join Date: Jan 2009
Posts: 7
Quote:
Originally Posted by root4 View Post

The wrong part is to declare i as a pointer (or an array, nevermind), because the compiler assumes it is not an alias to s, replacing int i[1]; by int i; in the union, and *f.i=0x2..2 by f.i=0x2..2 produces the correct result with -O2 and no additional option (because the compiler knows s and i are related).
If there is something bad in the union, how to explain the next code.
Code:
#include <stdio.h>

typedef union {
    short s[2];
    int i;
}foo;

int main()
{

    foo f;
    short *a = f.s;
    int * b = &f.i;
    int   cnt = 0x22222222;;

    f.s[0]=0x1111;
    f.s[1]=0x1111;

    printf("%x %x\n", a[0], a[1]);
    printf("%x %x\n", f.s[0], f.s[1]);
    printf("\n");

   // f.i = cnt;
    *b = cnt;

    printf("%x %x\n", a[0], a[1]);
    printf("%x %x\n", f.s[0], f.s[1]);
    printf("\n");


    printf("%x %x\n", a[0], a[1]);
    printf("%x %x\n", f.s[0], f.s[1]);
    printf("\n");

    return 0;
}
The code results:
1111 1111
1111 1111

1111 1111
2222 2222

2222 2222
2222 2222
koushikyou is offline   Reply With Quote
Old 01-07-2009, 03:28 AM   #11
Registered User
 
Join Date: Apr 2008
Posts: 282
After a quick test, simply replacing "*f.i=..." by "f.i[0]=..." seems enough to tell the optimizer 'i' is an alias for 's'. Using 'i' as a pointer, knowing it is of a different type of 's' and using strict aliasing makes the optimizer thinks they are unrelated objects. So in fact, you don't even have to modify your union, ignore my comment about that.
root4 is offline   Reply With Quote
Old 01-07-2009, 03:31 AM   #12
Registered User
 
Join Date: Jan 2009
Posts: 7
Quote:
Originally Posted by matsp View Post
I expect it ALWAYS assumes members are aliased - since storing different forms of data aliased is the exact purpose of unions.

--
Mats
I agree with you.
koushikyou is offline   Reply With Quote
Old 01-07-2009, 03:34 AM   #13
Registered User
 
Join Date: Apr 2008
Posts: 282
Yes, replace all occurences of 's' in what I told, by 'a'...

To sum up (how I see things, but I'm not expert on the topic):
's' and 'i' are aliases by default, 'a' is an alias of 's' when initialized, then 'i' is modified, it is accessed as a pointer and its type is _different_ of 'a', so the optimizer (strict aliasing) assumes those objects are no longer related, and applies its optimization (as details by King Mir probably). Same thing with the last example 'b'.

Last edited by root4; 01-07-2009 at 03:40 AM.
root4 is offline   Reply With Quote
Old 01-07-2009, 05:25 AM   #14
Registered User
 
Join Date: Jan 2009
Posts: 7
Is it a bad coding style or bug of gcc?
koushikyou is offline   Reply With Quote
Old 01-07-2009, 05:29 AM   #15
Kernel hacker
 
Join Date: Jul 2007
Location: Farncombe, Surrey, England
Posts: 15,686
Quote:
Originally Posted by koushikyou View Post
Is it a bad coding style or bug of gcc?
Depends on how you look at it - you are aliasing pointers, and gcc -O2 assumes "pointers do not alias" - if you want to avoid that, you should turn of that particular optimization step for the relevant code with -fno-strict-aliasing

But it is at the very least bad coding style to do this - even if it's technically not in itself incorrect and the C standard does certainly not forbid pointer aliases.

--
Mats
__________________
Compilers can produce warnings - make the compiler programmers happy: Use them!
Please don't PM me for help - and no, I don't do help over instant messengers.
matsp is offline   Reply With Quote
Reply

Tags
c o2 aliasing

Thread Tools
Display Modes

Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
Problem Compiling Flakster C++ Programming 4 06-13-2006 01:09 AM
Help on compiling code mattyp1977 C++ Programming 4 03-26-2006 05:07 PM
Problem : Threads WILL NOT DIE!! hanhao C++ Programming 2 04-16-2004 01:37 PM
Request for comments Prelude A Brief History of Cprogramming.com 15 01-02-2004 10:33 AM
Big Code, Little Problem CodeMonkey Windows Programming 4 10-03-2001 05:14 PM


All times are GMT -6. The time now is 08:53 AM.


Powered by vBulletin® Version 3.8.1
Copyright ©2000 - 2010, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.3.2

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22