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! ]
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
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.
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
> 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
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
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;
> 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
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
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'?
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 ]
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.
Because the braces in the if statement introduces a new scope.
See 3.3, in particular 3.3/1 and 3.3/2.
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
--
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
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)