Thread: Much ado about undefined statements

  1. #1
    Registered User
    Join Date
    Jul 2007
    Posts
    19

    Much ado about undefined statements

    I am currently involved in a HUGE discussion focused around statements like :

    Code:
     c = ++a + ++a;
    OR

    Code:
     c = ++a + a++;
    OR

    Code:
     c = a++ + a-- + ++a;
    .. and you get the idea.

    Anyone who knows something about sequence points will be able to answer this question really well.

    Further more, on page 79 of 550 of http://www.open-std.org/JTC1/SC22/WG...docs/n1124.pdf, we have something very similar mentioned by way of

    Code:
     i = i++;
    being undefined.

    I would like some good authority to assert that expressions I highlighted at the beginning are undefined (compiler dependent ?) too..

    From the preliminary searching I did, I saw "rules" like :

    1. The outcome is still undefined because according to the Standard, altering a modifiable lvalue more than once before a sequence point is reached causes undefined behaviour.

    2. Modifying the same variable using auto-increment/decrement more than once in the same statement gives undefined behaviour.

    Can someone give better explanation which go more deep into the standard ?

    I am also lookinf forward to a nice explanation on sequence points.

    I went through :

    http://en.wikipedia.org/wiki/Sequence_point

    and found it good. Anyone has anything more/better to add or say ?

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,662
    Well you seem to have access to all the good information there is (like the actual standard).

    Anyone who is arguing against that is quite frankly ........ing into the wind and wondering why they're all warm and wet.

    The phrase "more than once" says it all really.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User
    Join Date
    Jul 2007
    Posts
    19

    Nice way to phrase it...

    Nice way to phrase it...

    But seriously, when someone might be your senior project leader etc..

    You know... if I say that.. *I* might be in the wind....



    @Salem

    Nice summary your avtar does.. but in embedde systems, when main never returns to the system, we DO have void main().. any comments on that ?

  4. #4
    Deathray Engineer MacGyver's Avatar
    Join Date
    Mar 2007
    Posts
    3,210
    I'm just curious.... consider this off topic if you will, but what compiler would render the first two examples differently? The path to evaluate them would surely differ with some compilers, but wouldn't a and c contain the same values regardless once the evaluation is over?

  5. #5
    Registered User
    Join Date
    Jul 2007
    Posts
    19
    Nice approach...

    OK.. I am using Turbo C++ 3.0 AT MY END, and for the code :

    Code:
    #include <stdio.h>
    #include <conio.h>
    
    int main()
    {
    	int x = 5, y = 6, z = 0;
    
    	clrscr();
    
    	z = ++x + ++x;
    
    	printf("&#37;d %d", ((y++) * (++y) * (++y)), z);
    	/*                6    *  8    *   9   , (7 + 7) */
    
    	return 0;
    }
    I get the output :

    Code:
    432 14
    and for the snippet

    Code:
    #include <stdio.h>
    #include <conio.h>
    
    int main()
    {
    	int x = 5, y = 6, z = 0;
    
    	clrscr();
    
    	z = x++ + x++;
    
    	printf("%d %d", ((y++) * (y++) * (y++)), z);
    
    	return 0;
    }
    Code:
    336 10
    What does :

    1. MingW, GCC
    2. Visual C++ 6.0
    3. Visual C++ 2003

    .. etc ?

    I feel the results will differ?

  6. #6
    Woof, woof! zacs7's Avatar
    Join Date
    Mar 2007
    Location
    Australia
    Posts
    3,459
    First example,

    Quote Originally Posted by GCC 4.1
    392 14
    Second example
    Quote Originally Posted by GCC 4.1
    216 10
    Both compile with the following warnings:
    Quote Originally Posted by Invoked with gcc -W -Wall -ansi -pedantic -O2 test.c -o test.0.0.1.x86
    test.c:7: warning: operation on ‘x’ may be undefined
    test.c:9: warning: operation on ‘y’ may be undefined
    test.c:9: warning: operation on ‘y’ may be undefined
    Last edited by zacs7; 07-31-2007 at 04:15 AM. Reason: LCC results were wrong

  7. #7
    Deathray Engineer MacGyver's Avatar
    Join Date
    Mar 2007
    Posts
    3,210
    I think you're changing the conditions here. I was referring to the sole case of what you mentioned above. I didn't say anything about function calls or the like, which are clearly undefined and vary from compiler to compiler.

    BTW, I'm not trying to be smart or anything. While I wouldn't necessarily recommend writing code like that, I was just curious about this:

    Code:
    #include <stdio.h>
    
    int main(void)
    {
    	int c = 0, a = 5;
    	
    	c = ++a + ++a;
    	
    	printf("c = &#37;d\na = %d\n\n", c, a);
    	
    	return 0;
    }
    The line in question is what you originally mentioned. I'd just like to know what compilers will generate different output for the above program.

    Note: As I said, I'm not interested in writing crappy code that is undefined for real projects. This is just something I'm interested in asking.

    Edit:

    Found a pair that differ:

    LCC results in:

    Code:
    c = 13
    a = 7
    MinGW results in:

    Code:
    c = 14
    a = 7
    Last edited by MacGyver; 07-31-2007 at 04:02 AM.

  8. #8
    Registered User
    Join Date
    Jul 2007
    Posts
    19
    Ah ha !

    Just as I thought... classic example of undefined behaviour..

    But guys.. you know what would be better?

    Let's have a look at the corresponsing ASM produced by the expressions in question...

    Too bad Turbo C++ does not directly output ASM unlike other compilers... or does it and I don't know?

    Anyone interested in just discussing the ASM ??

  9. #9
    Registered User
    Join Date
    Jul 2007
    Posts
    19

    Talking

    Quote Originally Posted by MacGyver View Post

    Code:
    #include <stdio.h>
    
    int main(void)
    {
    	int c = 0, a = 5;
    	
    	c = ++a + ++a;
    	
    	printf("c = %d\na = %d\n\n", c, a);
    	
    	return 0;
    }
    The line in question is what you originally mentioned. I'd just like to know what compilers will generate different output for the above program.
    Turbo C++ 4.0 yeilds :

    Code:
    c = 14
    a = 7

  10. #10
    Registered User
    Join Date
    Jul 2007
    Posts
    19
    Another thing....

    If someone says

    Code:
    c = 13
    makes sense over

    Code:
    c = 14
    I would say, both are NONSENSE since the behaviour itself is undefined!

    However, just for the fun of it, I would love to have a look at what's really happening behind the scenes regarding the different answers we are all getting...

  11. #11
    Woof, woof! zacs7's Avatar
    Join Date
    Mar 2007
    Location
    Australia
    Posts
    3,459
    Since I like learning and stuff,
    here it is:
    Code:
    	.file	"test.c"
    	.section	.rodata.str1.1,"aMS",@progbits,1
    .LC0:
    	.string	"&#37;d %d"
    	.text
    	.p2align 4,,15
    .globl main
    	.type	main, @function
    main:
    	leal	4(%esp), %ecx
    	andl	$-16, %esp
    	pushl	-4(%ecx)
    	pushl	%ebp
    	movl	%esp, %ebp
    	pushl	%ecx
    	subl	$20, %esp
    	movl	$14, 8(%esp)
    	movl	$392, 4(%esp)
    	movl	$.LC0, (%esp)
    	call	printf
    	addl	$20, %esp
    	xorl	%eax, %eax
    	popl	%ecx
    	popl	%ebp
    	leal	-4(%ecx), %esp
    	ret
    	.size	main, .-main
    	.ident	"GCC: (GNU) 4.1.2 20061115 (prerelease) (SUSE Linux)"
    	.section	.note.GNU-stack,"",@progbits
    Compiled with gcc -W -S -Wall -ansi -pedantic -O2 test.c -o test

    Using example 1
    Code:
    #include <stdio.h>
    
    int main()
    {
    	int x = 5, y = 6, z = 0;
    
    	z = ++x + ++x;
    
    	printf("%d %d", ((y++) * (++y) * (++y)), z);
    
    	return 0;
    }

  12. #12
    Registered User
    Join Date
    Jul 2007
    Posts
    19
    @zacs7

    Boot into Windows and give us the LCC output too

  13. #13
    Deathray Engineer MacGyver's Avatar
    Join Date
    Mar 2007
    Posts
    3,210
    ASM? Absolutely.

    For the program I wrote (the simple one above, not your example), MinGW dumps the assembly to this, with optimizations turned off:

    Code:
            .file   "undef.c"
            .def    ___main;        .scl    2;      .type   32;     .endef
            .section .rdata,"dr"
    LC0:
            .ascii "c = &#37;d\12a = %d\12\12\0"
            .text
    .globl _main
            .def    _main;  .scl    2;      .type   32;     .endef
    _main:
            pushl   %ebp
            movl    %esp, %ebp
            subl    $24, %esp
            andl    $-16, %esp
            movl    $0, %eax
            addl    $15, %eax
            addl    $15, %eax
            shrl    $4, %eax
            sall    $4, %eax
            movl    %eax, -12(%ebp)
            movl    -12(%ebp), %eax
            call    __alloca
            call    ___main
            movl    $0, -4(%ebp)
            movl    $5, -8(%ebp)
            leal    -8(%ebp), %eax
            incl    (%eax)
            leal    -8(%ebp), %eax
            incl    (%eax)
            movl    -8(%ebp), %eax
            addl    -8(%ebp), %eax
            movl    %eax, -4(%ebp)
            movl    -8(%ebp), %eax
            movl    %eax, 8(%esp)
            movl    -4(%ebp), %eax
            movl    %eax, 4(%esp)
            movl    $LC0, (%esp)
            call    _printf
            movl    $0, %eax
            leave
            ret
            .def    _printf;        .scl    3;      .type   32;     .endef
    Key part is in bold.

    I would disagree with you and say that c = 13 makes sense, but that's because that's the way I personally evaluated it.

    I recognize the reason 14 is evaluated this way is because the compiler performs the increments one after the other and then does the add. So 5 is loaded, inc to 6, and then inc to 7. So now it adds a + a where a is 7. Adding produces 14. BTW, Borland's command line tools produced this value, too.

    LCC on the other hand.... their assembly output is cool because it intersperses the C with the assembly (never knew that ).

    Code:
    	.file	"\include\stdio.h"
    _$M0:
    	.file	"\undef.c"
    	.text
    	.file	"\include\safelib.h"
    _$M1:
    	.file	"\include\stdio.h"
    _$M2:
    	.file	"\undef.c"
    _$M3:
    	.text
    ;    1 #include <stdio.h>
    ;    2 
    ;    3 int main(void)
    	.type	_main,function
    _main:
    	pushl	%ebp
    	movl	%esp,%ebp
    	pushl	%ecx
    	pushl	%eax
    	pushl	%esi
    	pushl	%edi
    ;    4 {
    	.line	4
    ;    5 	int c = 0, a = 5;
    	.line	5
    	movl	$0,-8(%ebp)
    	movl	$5,-4(%ebp)
    ;    6 	
    ;    7 	c = ++a + ++a;
    	.line	7
    	movl	-4(%ebp),%edi
    	addl	$1,%edi
    	movl	%edi,-4(%ebp)
    	movl	-4(%ebp),%esi
    	addl	$1,%esi
    	movl	%esi,-4(%ebp)
    	addl	%esi,%edi
    	movl	%edi,-8(%ebp)
    ;    8 	
    ;    9 	printf("c = %d\na = %d\n\n", c, a);
    	.line	9
    	pushl	-4(%ebp)
    	pushl	-8(%ebp)
    	pushl	$_$2
    	call	_printf
    	addl	$12,%esp
    ;   10 	
    ;   11 	return 0;
    	.line	11
    	movl	$0,%eax
    _$1:
    ;   12 }
    	.line	12
    	popl	%edi
    	popl	%esi
    	leave
    	ret
    _$5:
    	.size	_main,_$5-_main
    	.globl	_main
    	.extern	_printf
    	.data
    _$2:
    ; "c = %d\na = %d\n\n\x0"
    	.byte	99,32,61,32,37,100,10,97,32,61,32,37,100,10,10,0
    LCC uses separate registers and separates the adding of the numbers. Loads 5, adds one. Loads 6, and adds one. Then adds 6 + 7 together to get 13.

    This is more fun than I thought. Get your project leader in on this discussion.
    Last edited by MacGyver; 07-31-2007 at 04:18 AM.

  14. #14
    Woof, woof! zacs7's Avatar
    Join Date
    Mar 2007
    Location
    Australia
    Posts
    3,459
    Sorry, turns out my LCC results were wrong (long story), I will compile it later (Under Wine not Windows - Windows is brokeded). g2g now.

    Quote Originally Posted by MacGyver
    LCC on the other hand.... their assembly output is cool because it intersperses the C with the assembly (never knew that ).
    You can do that in GCC,
    Q: How can I create a file where I can see the C code and its assembly translation together?
    A: Use the -S (note: capital S) switch to GCC, and it will emit the assembly code to a file with a .s extension. For example, the following command:

    gcc -O2 -S -c foo.c

    will leave the generated assembly code on the file foo.s.
    If you want to see the C code together with the assembly it was converted to, use a command line like this:

    gcc -c -g -Wa,-a,-ad [other GCC options] foo.c > foo.lst

    which will output the combined C/assembly listing to the file foo.lst.
    Last edited by zacs7; 07-31-2007 at 04:18 AM.

  15. #15
    Woof, woof! zacs7's Avatar
    Join Date
    Mar 2007
    Location
    Australia
    Posts
    3,459
    Anyway, GCC 4.1 without optimizations (So a comparison can be made)

    Code:
    	.file	"test.c"
    	.section	.rodata
    .LC0:
    	.string	"&#37;d %d"
    	.text
    .globl main
    	.type	main, @function
    main:
    	leal	4(%esp), %ecx
    	andl	$-16, %esp
    	pushl	-4(%ecx)
    	pushl	%ebp
    	movl	%esp, %ebp
    	pushl	%ecx
    	subl	$36, %esp
    	movl	$5, -16(%ebp)
    	movl	$6, -12(%ebp)
    	movl	$0, -8(%ebp)
    	addl	$1, -16(%ebp)
    	addl	$1, -16(%ebp)
    	movl	-16(%ebp), %eax
    	addl	-16(%ebp), %eax
    	movl	%eax, -8(%ebp)
    	addl	$1, -12(%ebp)
    	movl	-12(%ebp), %eax
    	imull	-12(%ebp), %eax
    	addl	$1, -12(%ebp)
    	movl	%eax, %edx
    	imull	-12(%ebp), %edx
    	addl	$1, -12(%ebp)
    	movl	-8(%ebp), %eax
    	movl	%eax, 8(%esp)
    	movl	%edx, 4(%esp)
    	movl	$.LC0, (%esp)
    	call	printf
    	movl	$0, %eax
    	addl	$36, %esp
    	popl	%ecx
    	popl	%ebp
    	leal	-4(%ecx), %esp
    	ret
    	.size	main, .-main
    	.ident	"GCC: (GNU) 4.1.2 20061115 (prerelease) (SUSE Linux)"
    	.section	.note.GNU-stack,"",@progbits
    And a C/ASM comparison: http://rafb.net/p/9fMLKs20.html
    Last edited by zacs7; 07-31-2007 at 04:27 AM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Undefined Reference Compiling Error
    By AlakaAlaki in forum C++ Programming
    Replies: 1
    Last Post: 06-27-2008, 11:45 AM
  2. C OpenGL Compiler Error?
    By Matt3000 in forum C Programming
    Replies: 12
    Last Post: 07-07-2006, 04:42 PM
  3. c++ linking problem for x11
    By kron in forum Linux Programming
    Replies: 1
    Last Post: 11-19-2004, 10:18 AM
  4. Problem with OpenGL tutorial
    By 2Biaz in forum Windows Programming
    Replies: 18
    Last Post: 09-16-2004, 11:02 AM
  5. qt help
    By Unregistered in forum Linux Programming
    Replies: 1
    Last Post: 04-20-2002, 09:51 AM