LinuxQuestions.org
Share your knowledge at the LQ Wiki.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 08-29-2009, 03:11 AM   #1
lemon09
Member
 
Registered: Jun 2009
Location: kolkata,India
Distribution: Mandriva,openSuse,Mint,Debian
Posts: 285
Blog Entries: 1

Rep: Reputation: 37
undefined in c


hello,

seemingly the following code:

Code:
int i=10,j=20
i= i++ + j++
should produce an output '30'...when the truth is that the output is '31'.

here i should mention that these are some undefined in C(K&R didn't say anything if such a situation arises).

nearly all the compilers(atleast for those which i have tested) produces an output of '31'.

can you please say how the compilers handle such a situation.

in java however you get the correct answer, i.e., 30.
why do the results differ when they are actually the same.
 
Old 08-29-2009, 06:05 AM   #2
Telemachos
Member
 
Registered: May 2007
Distribution: Debian
Posts: 754

Rep: Reputation: 60
I believe that C and its compilers don't want you to do multiple operations on the one item (the variable i) at the same time. If you add a third variable, everything is fine:

Code:
telemachus ~ $ cat count.c 
#include <stdio.h>

int main (void) {
    int i = 10;
    int j = 20;
    int k = 0;
    int x = 10;
    int y = 20;

    k = i++ + j++;
    printf("The total is %d.\n", k);

    
    x = x++ + y++;
    printf("The total is %d.\n", x);

    return 0;
}
telemachus ~ $ gcc -Wall --pedantic count.c -o count
count.c: In function ‘main’:
count.c:14: warning: operation on ‘x’ may be undefined
telemachus ~ $ ./count 
The total is 30.
The total is 31.
When the compiler says "operation on 'x' may be undefined", I usually take that as a sign that I did something wrong and need to change it.
 
Old 08-29-2009, 08:12 AM   #3
Sergei Steshenko
Senior Member
 
Registered: May 2005
Posts: 4,481

Rep: Reputation: 454Reputation: 454Reputation: 454Reputation: 454Reputation: 454
Quote:
Originally Posted by lemon09 View Post
hello,

seemingly the following code:

Code:
int i=10,j=20
i= i++ + j++
should produce an output '30'...when the truth is that the output is '31'.

here i should mention that these are some undefined in C(K&R didn't say anything if such a situation arises).

nearly all the compilers(atleast for those which i have tested) produces an output of '31'.

can you please say how the compilers handle such a situation.

in java however you get the correct answer, i.e., 30.
why do the results differ when they are actually the same.
Why do you think it should ? I.e. could you justify your expectations by clauses from, say, C99 standard ?
 
Old 08-29-2009, 09:01 AM   #4
jlinkels
LQ Guru
 
Registered: Oct 2003
Location: Bonaire, Leeuwarden
Distribution: Debian /Jessie/Stretch/Sid, Linux Mint DE
Posts: 5,195

Rep: Reputation: 1043Reputation: 1043Reputation: 1043Reputation: 1043Reputation: 1043Reputation: 1043Reputation: 1043Reputation: 1043
When i++ is used, it is said that variable i is increased 'after evaluation'. If it were increased before evaluation, the outcome would be 32 as both i and j are increased.

The difference that i seems to be increased before evaluation is obviously caused by using i as the result as well. Which is also demonstrated by the example of Telemachos.

It would be interesting to see the assembly code produced by the compiler, could someone do that? (I know it is possible, but I forgot long ago how to do that)

I am also wondering if there is some specification stating that this kind of evaluation is correct/not correct/undefined when the result is one of the operands.

Last, unless your goal is to write obfuscated code, it is best to avoid such statements. However from a scientific point of view it is certainly interesting to look into it.

jlinkels
 
Old 08-29-2009, 09:20 AM   #5
johnsfine
LQ Guru
 
Registered: Dec 2007
Distribution: Centos
Posts: 5,286

Rep: Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197
Quote:
Originally Posted by lemon09 View Post
can you please say how the compilers handle such a situation.

in java however you get the correct answer, i.e., 30.
why do the results differ when they are actually the same.
You can look at i=i++ + j++; as several separate operations, such as

1) temp = i + j
2) i++
3) j++
4) i = temp

But the sequence of those operations is not fully defined. We know 1 comes before any of 2, 3 or 4, but we don't know whether 2 comes before or after 3 or 4.

It is perfectly legitimate for the compiler to choose the sequence:
temp = i + j
i = temp
j++
i++

So 30 is not "the correct answer". It is one possible answer. 31 is an equally valid answer.
 
Old 08-29-2009, 09:24 AM   #6
Sergei Steshenko
Senior Member
 
Registered: May 2005
Posts: 4,481

Rep: Reputation: 454Reputation: 454Reputation: 454Reputation: 454Reputation: 454
Quote:
Originally Posted by jlinkels View Post
When i++ is used, it is said that variable i is increased 'after evaluation'. If it were increased before evaluation, the outcome would be 32 as both i and j are increased.

The difference that i seems to be increased before evaluation is obviously caused by using i as the result as well. Which is also demonstrated by the example of Telemachos.

It would be interesting to see the assembly code produced by the compiler, could someone do that? (I know it is possible, but I forgot long ago how to do that)

I am also wondering if there is some specification stating that this kind of evaluation is correct/not correct/undefined when the result is one of the operands.

Last, unless your goal is to write obfuscated code, it is best to avoid such statements. However from a scientific point of view it is certainly interesting to look into it.

jlinkels
AFAIK, this a classical example of undefined by standard behavior, and the compiler warns about it. Such code should be rejected.
 
Old 08-29-2009, 11:14 AM   #7
mrtiller
LQ Newbie
 
Registered: Aug 2009
Posts: 3

Rep: Reputation: 0
please see

http://www.parashift.com/c++-faq-lit...html#faq-39.15

on sequence points or the corresponding section of the C faq's (the discussion applies to both languages).
 
Old 08-29-2009, 11:38 AM   #8
paulsm4
LQ Guru
 
Registered: Mar 2004
Distribution: SusE 8.2
Posts: 5,863
Blog Entries: 1

Rep: Reputation: Disabled
I hate it when people want a reasonable explanation for completely unreasonable cases like this example.

To add insult to injury, Java does *not* "give the correct answer. The snippet as posted won't even *compile* in Java (and it may or may not compile in C - "it depends").

Why would anyone want to waste any time on silly, nonsensical, pointless questions like this?

If there's a pressing *need* to experiment in the land of "undefined behavior" - why not experiment on your own car (or any other handy motor vehicle)? Drain all the oil. Drive it around as long as you can. Does the engine seize up? Or does it just explode in a ball of flame? Why one and not the other?

Sigh...
 
Old 08-29-2009, 12:53 PM   #9
wje_lq
Member
 
Registered: Sep 2007
Location: Mariposa
Distribution: FreeBSD,Debian wheezy
Posts: 811

Rep: Reputation: 179Reputation: 179
Quote:
Originally Posted by paulsm4 View Post
Why would anyone want to waste any time on silly, nonsensical, pointless questions like this?
Because it's fun to play with mudpies.

When children do pointless things in play, it's easy to smile at them. But this is their work. This is the way they join battle with the universe. Their work is just as serious as our work.

When we play with undefined behavior in a C program, we are reappropriating for ourselves the wisdom we once had as children.

An aside: Toy C programs are cheap. Much cheaper than automobile engines.
 
Old 08-29-2009, 02:02 PM   #10
Sergei Steshenko
Senior Member
 
Registered: May 2005
Posts: 4,481

Rep: Reputation: 454Reputation: 454Reputation: 454Reputation: 454Reputation: 454
Quote:
Originally Posted by paulsm4 View Post
I hate it when people want a reasonable explanation for completely unreasonable cases like this example.

To add insult to injury, Java does *not* "give the correct answer. The snippet as posted won't even *compile* in Java (and it may or may not compile in C - "it depends").

Why would anyone want to waste any time on silly, nonsensical, pointless questions like this?

If there's a pressing *need* to experiment in the land of "undefined behavior" - why not experiment on your own car (or any other handy motor vehicle)? Drain all the oil. Drive it around as long as you can. Does the engine seize up? Or does it just explode in a ball of flame? Why one and not the other?

Sigh...
There is a wide spread opinion that if one faces such an interview question, he/she better run from the company where they ask such questions and expect anything but "undefined behavior".
 
Old 08-29-2009, 04:19 PM   #11
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
This must be unique to integral types, i.e. some sort of built-in operator ambiguity. Take the following example, compiled with g++:
Code:
#include <stdio.h>


class fake_int
{
public:
	fake_int(int vVal = 0) : self(++instance), value(vVal)
	{ fprintf(stderr, "[create %u (%i)]\n", self, value); }


	fake_int &operator = (const fake_int &rRight)
	{
	fprintf(stderr, "[set %u to %u (%i -> %i)]\n", self, rRight.self,
	  value, rRight.value);
	value = rRight.value;
	return *this;
	}


	fake_int operator + (const fake_int &rRight) const
	{
	fprintf(stderr, "[add %u and %u (%i and %i)]\n", self, rRight.self,
	  value, rRight.value);
	return fake_int(value + rRight.value);
	}


	fake_int operator ++ (int)
	{
	fprintf(stderr, "[post-increment %u (%i -> %i)]\n", self, value, value + 1);
	fake_int temp(value);
	++value;
	return temp;
	}


	int get_value() const
	{ return value; }


private:
	static unsigned int instance;

	const unsigned int self;
	int value;
};


unsigned int fake_int::instance = 0;


int main(int argc, char *argv[])
{
	fake_int i(10), j(20);
	i = i++ + j++;
	fprintf(stderr, "final value: %i\n", i.get_value());
}
gcc apparently doesn't react well to this sort of thing in general. For example:
Code:
#include <stdio.h>


int main()
{
	int i, j;

	i=10; j=20;
	i= i++ + j++;
	fprintf(stderr, "%i\n", i);

	*(unsigned char*) &i= 0x11;
	fprintf(stderr, "%i\n", i);
}
The underlined statement actually makes i++ in the italicized line cause a (different?) malfunction (on my system,) the underlined operation itself being valid (as far as I know.) I get 11 and 17, whereas commenting out the underlined line gives me 31 and 31. Removing ++ from i++ in the italicized line gives me 30 and 17. This is obviously something one shouldn't mess around with in real code.
Kevin Barry

edit:
If that weren't enough, try this one. I get 30!
Code:
#include <stdio.h>


int main()
{
	int i, j;

	i=10; j=20;
	fprintf(stderr, "%i\n", (i = i++ + j++));
}

Last edited by ta0kira; 08-29-2009 at 04:30 PM.
 
Old 08-29-2009, 04:29 PM   #12
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
Quote:
Originally Posted by paulsm4 View Post
Why would anyone want to waste any time on silly, nonsensical, pointless questions like this?
If someone happens upon something like this, whether intentionally or accidentally, they (like OP) will probably find the outcome counterintuitive. In a way OP is asking what it is about C and/or gcc that allows such an outcome, which alludes to the internal function of the compiler, to say the least. If the statement were compiled as one would expect from programming-language theory, the statement probably shouldn't result in 31; however, it does, which means something unexpected (to us) is going on with the compiler. Although "undefined" means "you'll get what I give you", that doesn't mean the gcc maintainers are snickering about how they can make this statement return 31; there must be a underlying logic that was intended to deal with something else, yet it expresses itself in the context in question.
Kevin Barry
 
Old 08-29-2009, 06:04 PM   #13
ntubski
Senior Member
 
Registered: Nov 2005
Distribution: Debian, Arch
Posts: 3,780

Rep: Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081
Quote:
If the statement were compiled as one would expect from programming-language theory, the statement probably shouldn't result in 31; however, it does, which means something unexpected (to us) is going on with the compiler.
I'm not sure what theory you refer to here, but 31 makes sense to my intuition. My understanding of x++ is that the increment happens after the statement is evaluated, so
Code:
i= i++ + j++;
 is equivalent to 
i = i + j; i += 1; j += 1;
It just so happens that this corresponds to what gcc compiles to, but as mrtiller already pointed out, this is a well known violation of the standard. The key phrase is "SEQUENCE POINTS". It's in the C faq too.

Quote:
This must be unique to integral types, i.e. some sort of built-in operator ambiguity. Take the following example, compiled with g++:
Overloaded operators are functions, and function calls are sequence points.

Quote:
*(unsigned char*) &i= 0x11;
Doing just (void) &i; is enough to get 11, it seems taking the address of a variable causes gcc to generate different (and more convoluted) code for incrementing. In particular, it uses LEA (on a register holding the old value of i) instead of ADD.

Quote:
If that weren't enough, try this one. I get 30!
Well, you weren't printing i, you printing the value of the assignment expression which is the value of the sum, so of course you get 30.

Code:
#include <stdio.h>
int main()
{
    int i, j;
    i=10; j=20;
    fprintf(stderr, "%i\n", (i = i++ + j++));
    fprintf(stderr, "%i\n", i);
}
This outputs
30
31
 
Old 08-29-2009, 06:59 PM   #14
jlinkels
LQ Guru
 
Registered: Oct 2003
Location: Bonaire, Leeuwarden
Distribution: Debian /Jessie/Stretch/Sid, Linux Mint DE
Posts: 5,195

Rep: Reputation: 1043Reputation: 1043Reputation: 1043Reputation: 1043Reputation: 1043Reputation: 1043Reputation: 1043Reputation: 1043
Quote:
Originally Posted by paulsm4 View Post
I hate it when people want a reasonable explanation for completely unreasonable cases like this example.
I am not sure that it is so unreasonable. It compiles correctly, so why not trying to explain what goes wrong.

Quote:
Originally Posted by paulsm4 View Post
Why would anyone want to waste any time on silly, nonsensical, pointless questions like this?
Because when you understand something it is much easier to remember. And increase general understanding which might help to avoid similar mistakes in the future. Great inventions were done trying to understand why something didn't work as expected.

Personally, I spend some of my time playing around with totally useless things, weird C constructs was one of them when I was still regularly programming in C. And ...uhm if you look on the internet for totally useless scientific or technical experiments, I bet you'll find quite a few hits.

jlinkels
 
Old 08-29-2009, 06:59 PM   #15
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
Quote:
Originally Posted by ntubski View Post
I'm not sure what theory you refer to here, but 31 makes sense to my intuition. My understanding of x++ is that the increment happens after the statement is evaluated, so
What sense does it make to pull the post-increment operator entirely out of the statement it exists in? It's a unary operator after all, not to mention that's a violation of operator precedence*. The only thing of lower precedence than assignment is comma, and post-increment is ahead of addition. Additionally, the standard post-increment operation is to copy the object, increment the value, and return the copy (that's the theory I'm talking about.)
Quote:
Originally Posted by ntubski View Post
Doing just (void) &i; is enough to get 11, it seems taking the address of a variable causes gcc to generate different (and more convoluted) code for incrementing. In particular, it uses LEA (on a register holding the old value of i) instead of ADD.


Well, you weren't printing i, you printing the value of the assignment expression which is the value of the sum, so of course you get 30.

Code:
#include <stdio.h>
int main()
{
    int i, j;
    i=10; j=20;
    fprintf(stderr, "%i\n", (i = i++ + j++));
    fprintf(stderr, "%i\n", i);
}
This outputs
30
31
It was merely observational information to demonstrate inconsistencies. Clearly the post-increment operations should occur within the (), which doesn't seem to be the case. Because this is undefined, however, *it makes sense to optimize out the stack space used by actually copying and incrementing in favor of putting i into a register for the addition, then incrementing at the end.
Kevin Barry
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
PHP Problem ('undefined index', 'undefined function') zokken Programming 2 12-04-2008 10:18 AM
undefined screen matt81 Slackware 2 09-13-2007 10:41 PM
undefined reference? Sharky01252 Programming 3 11-07-2006 11:36 AM
undefined reference vkmgeek Programming 1 05-11-2006 06:37 AM
Undefined Reference ChemicalBurn Programming 2 02-14-2005 03:01 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 11:52 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration