Use an undefinied variable

P

pierozanetti

Hi,
I have a question. This statement is accepted by the g++ compiler (v.
4.1.2, under linux):

char c = 'a';
string s = s + c;

But the variable s is used before being defined! Why? It's correct?

The program aborts when the statement is reached.
If we change the above code into:

string s = s + 'a';

the error changes. A segmentation fault is raised.
Can anyone tell me why the code is accepted by the compiler?
Thanks

Piero Zanetti
 
L

Lionel B

Hi,
I have a question. This statement is accepted by the g++ compiler (v.
4.1.2, under linux):

char c = 'a';
string s = s + c;

But the variable s is used before being defined! Why? It's correct?

It's valid code, but invokes undefined behaviour (actually I was a little
surprised that g++ doesn't emit a warning even with -std=c++98 -pedantic -
Wall).
The program aborts when the statement is reached. If we change the above
code into:

string s = s + 'a';

the error changes. A segmentation fault is raised.

Still undefined behaviour.
Can anyone tell me
why the code is accepted by the compiler?

Because it's valid code.
 
P

pierozanetti

It's valid code, but invokes undefined behaviour (actually I was a little
surprised that g++ doesn't emit a warning even with -std=c++98 -pedantic -
Wall).




Still undefined behaviour.


Because it's valid code.

Use an undefined variable is a valid code?!? I'm a little surprised.
The s+c expression is evaluated before the assignment. s is not
defined yet. so what's the different
with a programs like this

int main(){ cout(k); int k = 1;}

I also use the r-value of k, before being defined! ;)

Piero Zanetti
 
L

Lionel B

Use an undefined variable is a valid code?!?

Yes. To make it clear:

"valid" == complies with the C++ standard
"valid" != does something sensible

For instance this is valid code:

int main()
{
int x = 0/0;
}

Sure, it's extremely silly code (and my compiler issues a couple of
warnings) but it compiles.
 
B

Bart van Ingen Schenau

Hi,
I have a question. This statement is accepted by the g++ compiler (v.
4.1.2, under linux):

char c = 'a';
string s = s + c;

But the variable s is used before being defined! Why? It's correct?

Actually, the variable s is defined (otherwise the compiler would
complain), butit is not initialised yet when you try to use it.
This cause undefined behaviour.

You can split the declaration
string s = s + c;
in two parts.
The first part
string s
defines a variable called s. When the compiler has processed this, the
name s is know to refer to a variable of type string.
The second part
= s + c;
specifies how the variable should be initialised. The name s is known
here, so you could use it, but most uses will cause UB.
The program aborts when the statement is reached.
If we change the above code into:

string s = s + 'a';

the error changes. A segmentation fault is raised.
Can anyone tell me why the code is accepted by the compiler?

It is accepted, because it is syntactically valid.
Thanks

Piero Zanetti

Bart v Ingen Schenau
 
R

Ron Natalie

pierozanetti said:
Use an undefined variable is a valid code?!?


He means "well formed." That is, the compiler is not required
to detect and issue a diagnositc for it.
 
K

Kai-Uwe Bux

Lionel said:
Yes. To make it clear:

"valid" == complies with the C++ standard
"valid" != does something sensible

For instance this is valid code:

int main()
{
int x = 0/0;
}

Sure, it's extremely silly code (and my compiler issues a couple of
warnings) but it compiles.

I think your example is actually ill-formed according to [5/5]

If during the evaluation of an expression, the result is not
mathematically defined or not in the range of representable values for
its type, the behavior is undefined, unless such an expression is a
constant expression (5.19), in which case the program is ill-formed.

The 0/0 is a constant expression for which the result is not mathematically
defined; and so the program is ill-formed.


Best

Kai-Uwe Bux
 
L

Lionel B

Lionel said:
Yes. To make it clear:

"valid" == complies with the C++ standard "valid" != does something
sensible

For instance this is valid code:

int main()
{
int x = 0/0;
}

Sure, it's extremely silly code (and my compiler issues a couple of
warnings) but it compiles.

I think your example is actually ill-formed according to [5/5]

If during the evaluation of an expression, the result is not
mathematically defined or not in the range of representable values for
its type, the behavior is undefined, unless such an expression is a
constant expression (5.19), in which case the program is ill-formed.

The 0/0 is a constant expression for which the result is not
mathematically defined; and so the program is ill-formed.

Interesting... in that case shouldn't g++ report an error then rather
than just emit a warning?

$ g++ -std=c++98 main.cpp
main.cpp: In function ‘int main()’:
main.cpp:13: warning: division by zero in ‘0 / 0’
$
 
J

Juha Nieminen

pierozanetti said:
The s+c expression is evaluated before the assignment.

Nitpicking, but there's no assignment in an expression like
"std::string s = something;", only a constructor call.
 
J

Juha Nieminen

Lionel said:
It's valid code, but invokes undefined behaviour (actually I was a little
surprised that g++ doesn't emit a warning even with -std=c++98 -pedantic -
Wall).

How about this:

struct A { int i; A(): i(7) { std::cout << i << "\n"; } }(A);

Seems to compile and run ok with gcc. Is it valid?
 
L

Lionel B

How about this:

struct A { int i; A(): i(7) { std::cout << i << "\n"; } }(A);

Seems to compile and run ok with gcc. Is it valid?

Perhaps I should clarify that by "valid" I mean conforms to the language
standard; i.e. has no syntax errors, is well-formed, whatever you'd like
to call it. So if a program compiles under a compiler that conforms
perfectly to the standard (probably such a compiler doesn't exist) then
it is by definition valid. Whether it runs "ok" (whatever that means) has
no bearing on its validity.

Your example compiles ok for me, prints out "7" to std output and I can't
see any syntax errors.

What point were you trying to make?
 
D

Dario Saccavino

How about this:

struct A { int i; A(): i(7) { std::cout << i << "\n"; } }(A);

Seems to compile and run ok with gcc. Is it valid?

The problem here is not with objects initialized via their default
constructor. Writing "std::string s;" has well defined behaviour, even
if s doesn't seem to be initialized, because std::string defines a
default constructor that initializes the object to the null string.

In the OP the question is whether it is possible to use an object
before its construction. The code
string s = s + 'a';
does the following:
- call operator+(s,'a') and assign the result to a temporary variable.
- call string's copy constructor on s, with the temporary as
parameter.

The code above is allowed by the standard, although its behaviour is
undefined: it's more or less like
char temp[sizeof(string)];
string &s = *reinterpret_cast<string *>(temp);
new(temp) string(s + 'a');
but while, in the latter, the use of reinterpret_cast and placement
new shows that the programmer really wants to do something strange,
the OP's code is clearly an error, and some people (like me) are
worried by the fact that some compilers (g++, VS8.0, Comeau) accept it
and don't even issue a warning.

The interesting issue is that the same compilers complain when the
programmer writes
int i = i + 42;
with a "variable is used before it is initialized" warning.

Why? Is this a problem in the compiler, or a problem in the standard?

Dario
 
P

Pete Becker

Interesting... in that case shouldn't g++ report an error then rather
than just emit a warning?

The standard requires "a diagnostic." It doesn't distinguish between a
"warning" and an "error".
 
D

Default User

Lionel said:
Interesting... in that case shouldn't g++ report an error then rather
than just emit a warning?

The standard says nothing about errors or warnings. There are required
diagnostics. The actual output is strictly a QOI issue. A perfectly
comforming implementation could output: "this is a diagnostic" for
every case.





Brian
 
J

James Kanze

It's valid code, but invokes undefined behaviour (actually I
was a little surprised that g++ doesn't emit a warning even
with -std=c++98 -pedantic - Wall).

If it invokes undefined behavior, it's not valid code.
Still undefined behaviour.
Because it's valid code.

There's no syntax error, but it's still not legal code.

In this particular case, the standard allows using the variable
being defined in an initialization expression because there are
things you can legally do with. Something like:
void *p = &p ;
for example, is perfectly legal, valid and well defined. In the
case in question, I imagine that the compiler stops looking when
it sees that all we're doing is passing a reference (almost
certainly implemented as a pointer) to a function. If all the
function does is store that reference as a pointer, no problem.
It's only because the function actually uses what is referred to
that we have undefined behavior.
 
J

James Kanze

The standard requires "a diagnostic." It doesn't distinguish
between a "warning" and an "error".

It does require that the implementation document what is a
diagnostic in the sense of the standard. In the case of g++,
the documentation clearly says that any text appearing on
standard out or standard error is a diagnostic. Not very
useful, as documentation goes, and one could argue about it in
terms of quality of implementation, but certainly conform (and
the quality of the documentation of "implementation defined
behaviors" is a serious problem with almost all
implementations).
 
J

James Kanze

The standard says nothing about errors or warnings. There are
required diagnostics. The actual output is strictly a QOI
issue. A perfectly comforming implementation could output:
"this is a diagnostic" for every case.

Or just a question mark:). (An implementation is required to
document what it considers a diagnostic.) Also, an
implementation is allowed to output diagnostics for legal
programs.
 
D

Default User

James said:
Or just a question mark:). (An implementation is required to
document what it considers a diagnostic.)

Or, "your code stinks and so do you."
Also, an
implementation is allowed to output diagnostics for legal
programs.

And frequently do. Notably, the perfectly legal code:

int a = 0;

if (a = 1)
{
// do stuff
}


This will trigger a diagnostic on many implementations.



Brian
 
J

James Kanze

On 7 Mar, 17:02, Juha Nieminen <[email protected]> wrote:

[...]
The interesting issue is that the same compilers complain when the
programmer writes
int i = i + 42;
with a "variable is used before it is initialized" warning.
Why? Is this a problem in the compiler, or a problem in the
standard?

The standard says that both are undefined behavior. Whatever
the compiler does when it encounters them is correct, as far as
the standard is concerned. In the case above, the compiler sees
that you're using the variable before initialization, in a way
not allowed by the standard. In the original case, all the
compiler "sees" is that you're passing a reference to the
variable to a function, before the variable has been
constructed. Whether there is undefined behavior or not depends
on how the reference is used in the function.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,176
Messages
2,570,950
Members
47,503
Latest member
supremedee

Latest Threads

Top