Strange - a simple assignment statement shows error in VC++ but worksin gcc !

J

James Kuyper

Ezekiel said:
sun:~>g++ --version
g++ (GCC) 3.4.1
Copyright (C) 2004 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

sun:~>g++ foo.cpp
foo.cpp: In function `int main(int, char**)':
foo.cpp:6: error: invalid conversion from `void*' to `char*'
sun:~>

6: char* buff = malloc(512);

He specified "perfectly legal code". You're compiling it as C++ code
(which is off-topic in comp.lang.c, though probably not in the other
cross-posted groups). In C++, that code does not qualify: it violates a
constraint.
 
R

Rainer Weikusat

Ezekiel said:
[...]
Do you have an example where adding a cast to perfectly legal code
silences a warning?

sun:~>g++ --version
g++ (GCC) 3.4.1
Copyright (C) 2004 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

sun:~>g++ foo.cpp
foo.cpp: In function `int main(int, char**)':
foo.cpp:6: error: invalid conversion from `void*' to `char*'
sun:~>

6: char* buff = malloc(512);

This isn't 'legal' C++. It is legal C.
 
E

Ezekiel

James Kuyper said:
He specified "perfectly legal code". You're compiling it as C++ code
(which is off-topic in comp.lang.c, though probably not in the other
cross-posted groups). In C++, that code does not qualify: it violates a
constraint.

Now I understand... it needs to be "perfectly legal *C* code" - thanks for
clarifying the ground rules.

How's this?

sun:~>gcc --version
gcc (GCC) 3.4.1
Copyright (C) 2004 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

sun:~>gcc foo.c
foo.c: In function `main':
foo.c:6: warning: integer overflow in expression
sun:~>

6: unsigned int x = 3*1000*1000*1000;


Perhaps it's not legal but I'm declaring this as a unsigned int and not an
'integer' so why the overflow warning?
 
R

Rainer Weikusat

Keith Thompson said:
You were doing great until point 3.

Not really. Everything "might" be an error (compiler has now way to
tell if an addition should not really have been a
substraction). Consequently, the only "compiler which doesn't ignore
things which might be errors" is one which is guaranteed to only ever
output diagnostics. Even really grotty, old code (eg the some parts of
Kerberos) can be compiled without generating "lots of noise". The
friendly assumption that code written by me usually does is
wrong. (Almost no) Warnings can safely be ignored, based on their text
alone. I can only wonder who could come up with an idea like
this. Lastly, this sermon was hooked to my text without a particular
reason and partially contradicts it (eg I wrote that I consider "if in
doubt, emit a warning" a sensible policy).
 
U

Ulrich Eckhardt

[Note: dropping comp.os.linux.advocacy, where this is absolutely OT]

Keith said:
You were doing great until point 3. Adding a cast to silence a
warning is almost always a bad idea. (Incidentally, there's no such
thing as an "implicit cast". A cast is an operator that specifies a
conversion; you can have an implicit conversion.)

Actually, I agree with point 3. If possible, just use the correct type all
along, i.e. don't store the returnvalue of strlen() in an int. This is in
many cases already enough to reduce the number of warnings significantly
without casting and without cluttering the code otherwise.

Now, concerning explicit conversions, consider this:

int x = round(some_value);

Some compilers will complain that this conversion is lossy, and they are
right. If you know that this doesn't matter, using a cast can be helpful.
Of course, my first thought would be to avoid the conversion, as per my
initial comment.

Just for the record: in C++, I might actually write this instead:

int x = round<int>(some_value);

....and define the function accordingly so that it returns the correct type,
hiding the casting and validation inside.

Uli
 
K

Keith Thompson

Ezekiel said:
sun:~>g++ --version
g++ (GCC) 3.4.1
Copyright (C) 2004 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

sun:~>g++ foo.cpp
foo.cpp: In function `int main(int, char**)':
foo.cpp:6: error: invalid conversion from `void*' to `char*'
sun:~>

6: char* buff = malloc(512);

Ok, do you have an example in C? (I'm reading and posting in
comp.lang.c.)

In C, the conversion from void* to char* is implicit, and using a cast
is widely considered to be poor style. In C++, you should almost
certainly be using "new" rather than malloc.

And even in C++, the cast turns invalid code into valid code. We were
talking about adding a cast to code that's already "perfectly legal"
for the purpose of conveying information to the compiler.
 
J

Joe Pfeiffer

Ezekiel said:
sun:~>gcc --version
gcc (GCC) 3.4.1
Copyright (C) 2004 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

sun:~>gcc foo.c
foo.c: In function `main':
foo.c:6: warning: integer overflow in expression
sun:~>

6: unsigned int x = 3*1000*1000*1000;


Perhaps it's not legal but I'm declaring this as a unsigned int and not an
'integer' so why the overflow warning?

Because your operands are signed ints, so you're telling the compiler
to perform several signed multiplications (which overflow) and then
implicitly convert the result to an unsigned int.

viper:229% cat bogus.c
int main()
{
unsigned int x = 3U*1000U*1000U*1000U;
}
viper:230% gcc bogus.c
viper:231%

(I don't remember whether the interpretation of the numbers as
'signed' rather than 'unsigned' is required or
implementation-specific, but I've never seen one that treated them as
unsigned)
 
I

Ian Collins

Richard said:
Keith Thompson said:
Visual Studio warned about a "possible loss of information", despite
the fact that I knew for sure, from my wider perspective, that no
information could possibly be lost. Adding a cast suppressed the
warning. (I checked this.) But then I removed the cast and used a
comment instead. It shouldn't be that big a deal to find the - oh,
hang on... aha! Here we are - I just remembered what it was, and
guess what? The code is portable, and there's a copy right here.
It's in bignum code. Okay...

/* Some compilers warn about possible loss of data.
* But Hexit only returns values in the range 0x0-0xF.
* So it's okay. A cast would be unnecessary and ugly.
*/
tmp = itmp;

itmp is an int, and tmp is an unsigned char. The only possible
values itmp can have are 0 to 15, and all those values will fit in
an unsigned char (not at the same time, obviously).

So would "unsigned char c = toupper( n );" give the same warning?
 
J

jameskuyper

Ezekiel said:
Now I understand... it needs to be "perfectly legal *C* code" - thanks for
clarifying the ground rules.

Actually, he didn't specify that. I'd guess that's because he was
reading the message in comp.lang.c, and was not thinking about the
other newsgroups that this message is posted two where it might be
less obvious that he was talking about C code.

However, it should have been quite clear that it should be perfectly
legal code for whichever language it was being compiled as.
How's this?

sun:~>gcc --version
gcc (GCC) 3.4.1
Copyright (C) 2004 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

sun:~>gcc foo.c
foo.c: In function `main':
foo.c:6: warning: integer overflow in expression
sun:~>

6: unsigned int x = 3*1000*1000*1000;


Perhaps it's not legal but I'm declaring this as a unsigned int and not an
'integer' so why the overflow warning?

Try again. Each of those intger literals has type 'int'. Therefore,
the multiplicaions are carried out in type 'int' before the result is
converted to unsigned int. It is those multiplications that mean that
your program has undefined behavior.
 
C

CBFalconer

James said:
.... snip ...

You will need a better example to make your point. Either the
second if is redundant, or initialization of somevar is not
guaranteed. If you remove the second if(), a reasonably
sophisticated compiler will recognize, at least, that somevar
might have been initialized.

Even modifying as you suggest, as seen below, a good compiler won't
recognize that it MAY have been initialized, but will recognize
that it MAY NOT have initialized, and warn accordingly.
void func(int i_mode){
int somevar;

if (i_mode == 1) do_something(&somevar);
else do_otherthing(&somevar);
process_result(somevar);
}

Of course, changing the "void do_*(int *val);" functions to:

int do_*(void);

functions will fix that:

if (i_mode == 1) somevar = do_something(void);
else somevar = do_otherthing(void);
process_result(somevar);

and the compiler can tell that with ease.
 
C

CBFalconer

Ian said:
Richard Heathfield wrote:
.... snip ...


So would "unsigned char c = toupper( n );" give the same warning?

Yes. toupper returns an int. toupper(EOF) is legitimate, and the
result would not fit.
 
K

Keith Thompson

CBFalconer said:
if (i_mode == 1) somevar = do_something(void);
else somevar = do_otherthing(void);
process_result(somevar);
[...]

Syntactic quibble: the (void) is part of the syntax for the
declaration, but is not allowed in a call. You just want
do_something().
 
C

CBFalconer

Keith said:
CBFalconer said:
if (i_mode == 1) somevar = do_something(void);
else somevar = do_otherthing(void);
process_result(somevar);
[...]

Syntactic quibble: the (void) is part of the syntax for the
declaration, but is not allowed in a call. You just want
do_something().

It's handy having a compiler around to do those quibbles. :)
 
J

James Kuyper

CBFalconer said:
James Kuyper wrote:
... snip ...

Even modifying as you suggest, as seen below, a good compiler won't
recognize that it MAY have been initialized, but will recognize
that it MAY NOT have initialized, and warn accordingly.

There's three possibilities: the compiler can be certain that a variable
will be used while uninitialized, the compiler can be certain that the
variable will not be used while uninitialized, and the compiler can't be
certain either way. The original code falls into the first category,
which should certainly produce at least a warning message. Removal of
the second if() statement moves it into the third category, where it's
more debatable whether a warning is needed. On a decent compiler, it
should be optional whether or not a warning is produced in the third case.
 
J

jameskuyper

James said:
There's three possibilities: the compiler can be certain that a variable
will be used while uninitialized, the compiler can be certain that the
variable will not be used while uninitialized, and the compiler can't be
certain either way. ...
... The original code falls into the first category,
which should certainly produce at least a warning message. Removal of
the second if() statement moves it into the third category,

I didn't pay enough attention to the actual code I was talking about
when I wrote those two statements. The original code clearly contains
either redundant code, or defective code, depending upon what
guarantees there are about the value of i_mode. My suggested
modification deals with that problem, but does nothing about the
uncertainties about the definitions of the subroutines.

The implementation still does not know (at least until link time)
whether or not do_something(&somevar) or do_otherthing(&somevar)
actually write to the locations pointed at by their arguments before.
Therefore, both the original code and the modified code are in the
third category.
 
K

karthikbalaguru

Alex Blekhman said:
Rainer Weikusat said:
Not in this particular case: The C language definition demands
(6.5.4|3) that converting from int ** (or int *[]) to int * is
done by explicit casting.
Apparently both compilers relax this requirement and accept the
code, though with warning. Probably compiling in ANSI
compatibility mode will produce an error.

No, the only requirement is that the compiler must produce a
diagnostic.  Once that diagnostic has been produced, the compiler is
free either to reject the translation unit or to continue translating
it; in the latter case, the behavior of the program is not defined by
the standard.  There is no relaxation of the requirement, just
different ways of conforming to it.

Followups to comp.lang.c.

I came across the below in Section 6 of C FAQ.
" Some compilers have a switch controlling whether string literals are
writable or
not (for compiling old code), and some may have options to cause
string literals
to be formally treated as arrays of const char (for better error
catching). "

And hence the gcc supports it .

Karthik Balaguru
 
K

Keith Thompson

karthikbalaguru said:
Alex Blekhman said:
:
Not in this particular case: The C language definition demands
(6.5.4|3) that converting from int ** (or int *[]) to int * is
done by explicit casting.
Apparently both compilers relax this requirement and accept the
code, though with warning. Probably compiling in ANSI
compatibility mode will produce an error.

No, the only requirement is that the compiler must produce a
diagnostic.  Once that diagnostic has been produced, the compiler is
free either to reject the translation unit or to continue translating
it; in the latter case, the behavior of the program is not defined by
the standard.  There is no relaxation of the requirement, just
different ways of conforming to it.

Followups to comp.lang.c.

I came across the below in Section 6 of C FAQ.
" Some compilers have a switch controlling whether string literals are
writable or
not (for compiling old code), and some may have options to cause
string literals
to be formally treated as arrays of const char (for better error
catching). "

And hence the gcc supports it .

And when either of these options is enabled, gcc is not a conforming
C compiler, because it fails to produce required diagnostics.
 
F

Flash Gordon

Keith said:
And when either of these options is enabled, gcc is not a conforming
C compiler, because it fails to produce required diagnostics.

Making the string literals writable does not affect what diagnostics are
produced and does not affect conformance. Treating them as const char
arrays does. So only one of those options breaks conformance.
 
I

Ike Naar

And when either of these options is enabled, gcc is not a conforming
C compiler, because it fails to produce required diagnostics.

With the latter option, the compiler will emit a diagnostic
("warning: initialization discards qualifiers from pointer target type")
for a program that is actualy valid C and does not need a diagnostic.
That behaviour, in itself, does not make the compiler non-conforming.
 
I

Ike Naar

[email protected] (Ike Naar) said:
[about -Wwrite-strings]
the compiler will emit a diagnostic
("warning: initialization discards qualifiers from pointer target type")
for a program that is actualy valid C and does not need a diagnostic.
That behaviour, in itself, does not make the compiler non-conforming.

The -Wwrite-strings can cause it to omit the required diagnostic for
the following:

const char (*p)[6] = &"hello";

You are right. I hadn't thought of that.
 

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
473,774
Messages
2,569,596
Members
45,143
Latest member
SterlingLa
Top