Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Compiler bug? Two variables of same name in one scope

7 views
Skip to first unread message

Rune Allnor

unread,
Oct 30, 2007, 8:30:34 AM10/30/07
to
Hi folks.

Yesterday I modified some old code of mine, and ran into
trouble when I tested it. It turned out that I had renamed a
variable to a name that was already in use in the relevant
scope.Basically, the situation was as in this function:

double f(double a)
{
if(1)
{
double a = a; // <------------- This actually compiles...
}
return a;
}

The variable name was already used in the argument to
the function, and I had inadvertedly used the same name
for a variable inside an if-block. As in the example above,
I used the parameter version of the variable to initialize
the local version.

What surprised me after I found the cause of the bug
was that the compiler actually accepted that piece
of code without complaints. Is that a bug in my compiler
or is the above legal C++ code?

Rune


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Ulrich Eckhardt

unread,
Oct 30, 2007, 3:49:42 PM10/30/07
to
Rune Allnor wrote:
> double f(double a)
> {
> if(1)
> {
> double a = a; // <------------- This actually compiles...
> }
> return a;
> }
>
> The variable name was already used in the argument to
> the function, and I had inadvertedly used the same name
> for a variable inside an if-block. As in the example above,
> I used the parameter version of the variable to initialize
> the local version.

I think you didn't, you used the local variable 'a' to initialise itself.

> What surprised me after I found the cause of the bug
> was that the compiler actually accepted that piece
> of code without complaints. Is that a bug in my compiler
> or is the above legal C++ code?

Neither. Many compilers are able to tell you that you used 'a' before it was
initialised. However, IIRC the code causes undefined behaviour which is not
required to be diagnosed by the compiler. As such, of course it is not
legal C++ code.

Uli

--
Sator Laser GmbH
Geschäftsführer: Ronald Boers, Amtsgericht Hamburg HR B62 932

Francis Glassborow

unread,
Oct 30, 2007, 3:48:44 PM10/30/07
to
Rune Allnor wrote:
> Hi folks.
>
> Yesterday I modified some old code of mine, and ran into
> trouble when I tested it. It turned out that I had renamed a
> variable to a name that was already in use in the relevant
> scope.Basically, the situation was as in this function:
>
> double f(double a)
> {
> if(1)
> {
> double a = a; // <------------- This actually compiles...
> }
> return a;
> }
>
> The variable name was already used in the argument to
> the function, and I had inadvertedly used the same name
> for a variable inside an if-block. As in the example above,
> I used the parameter version of the variable to initialize
> the local version.
>
> What surprised me after I found the cause of the bug
> was that the compiler actually accepted that piece
> of code without complaints. Is that a bug in my compiler
> or is the above legal C++ code?
It is 'legal' code but has undefined behaviour. I.e the compiler is not
required to do anything helpful. The reason that this construct is
grammatically correct is that there has been no reasonable way to
prohibit it without also prohibiting some (rather subtle) uses of copy
ctors to chain objects together. By the time a got to write (some time
in the early 90s) a proposal to make

mytype mt = mt;

illegal it was already too late as valid working code already existed in
the field. In general a good code checker such as PCLint will identify
such code and issue a warning.

--
Note that robinton.demon.co.uk addresses are no longer valid.

Jonathan Leffler

unread,
Oct 30, 2007, 3:47:43 PM10/30/07
to
Rune Allnor wrote:
> [...] It turned out that I had renamed a

> variable to a name that was already in use in the relevant
> scope.

Strictly, no - the inner declaration is in a new scope.

> Basically, the situation was as in this function:
>
> double f(double a)
> {
> if(1)
> {
> double a = a; // <------------- This actually compiles...
> }
> return a;
> }
>
> The variable name was already used in the argument to
> the function, and I had inadvertedly used the same name
> for a variable inside an if-block. As in the example above,
> I used the parameter version of the variable to initialize
> the local version.
>
> What surprised me after I found the cause of the bug
> was that the compiler actually accepted that piece
> of code without complaints. Is that a bug in my compiler
> or is the above legal C++ code?

Perfectly legal in both C++ and C.

What wouldn't work is:

int f(int i)
{
int i = i;
}

--
Jonathan Leffler #include <disclaimer.h>
Email: jlef...@earthlink.net, jlef...@us.ibm.com
Guardian of DBD::Informix v2007.0914 -- http://dbi.perl.org/

publictimestamp.org/ptb/PTB-1664 tiger2 2007-10-30 12:00:04
0B6E76690C452063FCE29F8C9A1CBE78E473D91741919450

anon

unread,
Oct 30, 2007, 3:59:47 PM10/30/07
to
Rune Allnor wrote:

> double f(double a)
> {
> if(1)
> {
> double a = a; // <------------- This actually compiles...
> }
> return a;
> }
>
> The variable name was already used in the argument to
> the function, and I had inadvertedly used the same name
> for a variable inside an if-block. As in the example above,
> I used the parameter version of the variable to initialize
> the local version.
>
> What surprised me after I found the cause of the bug
> was that the compiler actually accepted that piece
> of code without complaints. Is that a bug in my compiler
> or is the above legal C++ code?

Which compiler? If g++ or gcc, then add these options:
-Wall -pedantic -Werror -Wuninitialized
and bugs of this type will be caught

Tjark Weber

unread,
Oct 30, 2007, 4:03:38 PM10/30/07
to
On Oct 30, 1:30 pm, Rune Allnor <all...@tele.ntnu.no> wrote:
> double f(double a)
> {
> if(1)
> {
> double a = a; // <------------- This actually compiles...
> }
> return a;
>
> }

This is legal C++ code, and it doesn't do what you might think. The
point of declaration for a name is immediately after its complete
delarator, i.e. immediately after "double a". This means that "double
a = a" will not only render the function parameter "a" invisible, but
it will also initialize the second variable "a" with its own
(indeterminate) value, rather than with the value of the function
parameter.

Lovely, isn't it?

Tjark

softwa...@gmail.com

unread,
Oct 30, 2007, 4:05:17 PM10/30/07
to
On Oct 30, 8:30 am, Rune Allnor <all...@tele.ntnu.no> wrote:
> Hi folks.
>
> Yesterday I modified some old code of mine, and ran into
> trouble when I tested it. It turned out that I had renamed a
> variable to a name that was already in use in the relevant
> scope.Basically, the situation was as in this function:
>
> double f(double a)
> {
> if(1)
> {
> double a = a; // <------------- This actually compiles...
> }
> return a;
>
> }


Its legal code. The visibility of the function argument a is masked by
the stack variable, a, local to the if block. You are creating a
double on the stack, a, which has an undefined value, and assigning it
to itself. It is equivalent to just doing:

double f(double a)
{
if(1)
{
double a;
}
return a;

aceh...@gmail.com

unread,
Oct 30, 2007, 4:04:53 PM10/30/07
to
On Oct 30, 5:30 am, Rune Allnor <all...@tele.ntnu.no> wrote:

> double f(double a)
> {
> if(1)
> {
> double a = a; // <------------- This actually compiles...
> }
> return a;
>
> }

[...]

> I used the parameter version of the variable to initialize
> the local version.

Unfortunately that's not true. You used the uninitialized local
version to initialize itself. :)

> What surprised me after I found the cause of the bug
> was that the compiler actually accepted that piece
> of code without complaints. Is that a bug in my compiler
> or is the above legal C++ code?

It is legal; as always, the inner name hides the outer name. There is
only one 'a' during that initialization. The following construct is
valid on its own:

void f()
{
double a = a;
}

You have an uninitialized 'a' at hand.

Ali

Seungbeom Kim

unread,
Oct 31, 2007, 11:57:41 AM10/31/07
to
Tjark Weber wrote:
> On Oct 30, 1:30 pm, Rune Allnor <all...@tele.ntnu.no> wrote:
>> double f(double a)
>> {
>> if(1)
>> {
>> double a = a; // <------------- This actually compiles...
>> }
>> return a;
>>
>> }
>
> This is legal C++ code, and it doesn't do what you might think. The
> point of declaration for a name is immediately after its complete
> delarator, i.e. immediately after "double a". This means that "double
> a = a" will not only render the function parameter "a" invisible, but
> it will also initialize the second variable "a" with its own
> (indeterminate) value, rather than with the value of the function
> parameter.
>
> Lovely, isn't it?

It's useful when you need the address of the object being initialised to
initialise itself:

struct node { node* ptr; /* ... */ };
node n = { &n, /* ... */ }; // a self-referring object

--
Seungbeom Kim

Rune Allnor

unread,
Oct 31, 2007, 12:06:14 PM10/31/07
to
Thanks, everyone, for your informative answers.

It seems my code example to some extent obfuscated
my main question, so I'll rephrase:

Given that

void f(double a)
{
if(1)
{
double a;
}
}

compiles with no compiler errors, why does the inner
declaration of the variable *not* cause a compiler
error due to multiple declarations of the variable 'a'?

Francis Glassborow

unread,
Oct 31, 2007, 12:06:07 PM10/31/07
to
softwa...@gmail.com wrote:
> On Oct 30, 8:30 am, Rune Allnor <all...@tele.ntnu.no> wrote:
>> Hi folks.
>>
>> Yesterday I modified some old code of mine, and ran into
>> trouble when I tested it. It turned out that I had renamed a
>> variable to a name that was already in use in the relevant
>> scope.Basically, the situation was as in this function:
>>
>> double f(double a)
>> {
>> if(1)
>> {
>> double a = a; // <------------- This actually compiles...
>> }
>> return a;
>>
>> }
>
>
> Its legal code. The visibility of the function argument a is masked by
> the stack variable, a, local to the if block. You are creating a
> double on the stack, a, which has an undefined value, and assigning it
> to itself. It is equivalent to just doing:

No it isn't
>
> double f(double a)
> {
> if(1)
> {
> double a;

This statement is perfectly OK, it just does not do anything useful.
However the
double a = a;
in the original has undefined behaviour and gives the compiler licence
to do anything it chooses to with your code. I believe there was an
early version of gcc that started up a game of nethack whenever it
determined that the program was exhibiting undefined behaviour.

> }
> return a;
> }
>
>


--
Note that robinton.demon.co.uk addresses are no longer valid.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Francis Glassborow

unread,
Oct 31, 2007, 7:27:39 PM10/31/07
to
Rune Allnor wrote:
> Thanks, everyone, for your informative answers.
>
> It seems my code example to some extent obfuscated
> my main question, so I'll rephrase:
>
> Given that
>
> void f(double a)
> {
> if(1)
> {
> double a;
> }
> }
>
> compiles with no compiler errors, why does the inner
> declaration of the variable *not* cause a compiler
> error due to multiple declarations of the variable 'a'?

For the same reason that

int i;

void f(){
int i;
}

Is OK. A declaration of the same name in a nested scope merely hides the
name from the outer scope.

red floyd

unread,
Oct 31, 2007, 7:27:34 PM10/31/07
to
Rune Allnor wrote:
> Thanks, everyone, for your informative answers.
>
> It seems my code example to some extent obfuscated
> my main question, so I'll rephrase:
>
> Given that
>
> void f(double a)
> {
> if(1)
> {
> double a;
> }
> }
>
> compiles with no compiler errors, why does the inner
> declaration of the variable *not* cause a compiler
> error due to multiple declarations of the variable 'a'?
>
>

Because the braces in the if statement introduces a new scope.

See 3.3, in particular 3.3/1 and 3.3/2.

Wu Yongwei

unread,
Nov 1, 2007, 2:48:28 PM11/1/07
to
On Oct 31, 3:48 am, Francis Glassborow

Interesting comment. Can you, or any other gurus here, show some
valid working code in this form? I really don't like it and can't
think of anything useful.

Best regards,

Yongwei


--

Rune Allnor

unread,
Nov 1, 2007, 5:42:31 PM11/1/07
to
On 1 Nov, 00:27, Francis Glassborow

<francis.glassbo...@btinternet.com> wrote:
> Rune Allnor wrote:
> > Thanks, everyone, for your informative answers.
>
> > It seems my code example to some extent obfuscated
> > my main question, so I'll rephrase:
>
> > Given that
>
> > void f(double a)
> > {
> > if(1)
> > {
> > double a;
> > }
> > }
>
> > compiles with no compiler errors, why does the inner
> > declaration of the variable *not* cause a compiler
> > error due to multiple declarations of the variable 'a'?
>
> For the same reason that
>
> int i;
>
> void f(){
> int i;
>
> }
>
> Is OK. A declaration of the same name in a nested scope merely hides the
> name from the outer scope.

I had to think about that for a while. What I came
up with is this:

/**************************************************************/
#include <iostream>
int i = 1; // 'i' is global variable
int main(int argc, char* argv[])
{
std::cout << i << std::endl; // print global 'i'
int i = 2; // declare local variable 'i'
std::cout << i << std::endl; // print local 'i'
return 0;
}
/**************************************************************/

So the same idea works on all levels of scopes.
Sorry for being so slow; I haven't used global
variables in the past so I didn't see the analogy.
Thanks for your patience.

Rune

Joel Yliluoma

unread,
Nov 16, 2007, 1:35:51 PM11/16/07
to
On Thu, 1 Nov 2007 12:48:28 CST, Wu Yongwei wrote:
>> Rune Allnor wrote:
>> > double a = a; // <------------- This actually compiles...
>
> Can you, or any other gurus here, show some valid working code in
> this form? I really don't like it and can't think of anything useful.

Examples that are similar to that:

int bit=1, byte=8*bit, kilobyte=1024*byte, megabyte=1024*kilobyte;

double* p = (double*) malloc(sizeof(*p) * 100); // allocate 100 doubles

class someobj
{
public:
someobj();
someobj(someobj* _myptr): myptr(_myptr) { }
void realloc() { *myptr = new someobj; delete this; }
private:
someobj* myptr;
};

someobj* o = new someobj( &o );
o->realloc(); // replaces o


(Ignore the fact that it's better to use new[] than
malloc, I'm just illustrating here.)

--
Joel Yliluoma - http://bisqwit.iki.fi/
: comprehension = 1 / (2 ^ precision)

0 new messages