Warnings in lcc-win

J

jacob navia

After a user asked for clarification about some warnings issued by
lcc-win, I have updated the compiler to reflect this discussion.

1) The buggy warning about
long l;
printf("%li", l * 10L);
is eliminated. This means that when you
write:
long l;
printf("%i", l*10L);
there will be no warning about expecting an
integer given a long. Better less warnings always correct
than more warnings sometimes incorrect. The alternative, i.e.
maintaining the type long internally when both long and int
are identical would be too much changes in the compiler.

2) I maintain two of the three warnings.

Warning tprintf.c: 4 old-style function definition for 'main'
Warning tprintf.c: 4 missing prototype for 'main'

but dropped the "non-ANSI" warning. A warning will be issued
if main differs from its ANSI prototype.

I thank all people that participated in this discussion and
the user that raised this question in the first place.

jacob
 
E

Eric Sosman

jacob navia wrote On 09/27/07 17:33,:
After a user asked for clarification about some warnings issued by
lcc-win, I have updated the compiler to reflect this discussion.

1) The buggy warning about
long l;
printf("%li", l * 10L);
is eliminated. This means that when you
write:
long l;
printf("%i", l*10L);
there will be no warning about expecting an
integer given a long. Better less warnings always correct
than more warnings sometimes incorrect. The alternative, i.e.
maintaining the type long internally when both long and int
are identical would be too much changes in the compiler.

Does the compiler really treat `int' and `long' as
identical? If so, what does it do with

int value = 42;
long *ptr = &value;
or with
extern long global;
extern int global;
or with
int func(void);
long func(void) { return 42L; }

? Diagnostics are required for these -- if the compiler
is able to emit them it must be "aware" at some level that
`int' and `long' are different, even though they share a
common representation.

Are other sets of types similarly confounded? For
example, is `char' a full-fledged type of its own, or is
it just an alias for `signed char' or `unsigned char'?
Are `struct f { int i; }' and `struct g { int i; }'
considered identical?

I hope things aren't as tangled as all that -- but
failing to distinguish between `int' and `long' makes
me fear that they might be.
 
J

Jack Klein

After a user asked for clarification about some warnings issued by
lcc-win, I have updated the compiler to reflect this discussion.

1) The buggy warning about
long l;
printf("%li", l * 10L);
is eliminated. This means that when you
write:
long l;
printf("%i", l*10L);

Surely here you meant "%li", again. If you are going to check *printf
format strings and warn about mismatches, "%i" is a mismatch for long,
even on implementations where both have the same size and
implementation.
there will be no warning about expecting an
integer given a long. Better less warnings always correct
than more warnings sometimes incorrect. The alternative, i.e.
maintaining the type long internally when both long and int
are identical would be too much changes in the compiler.

2) I maintain two of the three warnings.

Warning tprintf.c: 4 old-style function definition for 'main'
Warning tprintf.c: 4 missing prototype for 'main'

Let's talk about these.

I agree with the first one completely, assuming that it is not the
default and the user has asked for a higher warning level.

But I do not like the wording for the second one. I think it is
confusing, because the wording is not specific. I will describe what
I mean.

If the warning is given because the function definition:

return_type func() { /* body */ }

....does not provide a prototype, then I think better wording would be:

Warning filename.c: # definition does not provide a prototype for
'func'

This would distinguish it from a different warning:

Warning filename.c: # function defined without prototype in scope

I remember an old version of CodeWarrior that had an option to
generate this warning if it came across the definition of any
non-static function without having seen a prototype.

This was a nice option for limiting unnecessary external visibility.
If a function was only used in the source file where it was defined,
it could be defined before use as static and you did not get this
warning.

If the function truly needed external linkage, because it would be
called from other source files by name, then the defining source file
should be including a header with a prototype for it, the same header
the calling source file(s) would include.

CodeWarrior specifically exempted main() from this check.

I have not seen another compiler that offered this warning, but PC
Lint does.

So be more specific with your warning, I think you mean:

definition does not provide a prototype for func

....and consider adding, if lcc-win32 does not have it already, an
option to warn about the definition of a non-static function without a
prototype already in scope:

function func defined without prototype in scope

....but be sure to special case main() and exempt it if you do.

[posted and mailed]

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://c-faq.com/
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.club.cc.cmu.edu/~ajo/docs/FAQ-acllc.html
 
C

CBFalconer

Jack said:
.... snip ...

I agree with the first one completely, assuming that it is not
the default and the user has asked for a higher warning level.

But I do not like the wording for the second one. I think it is
confusing, because the wording is not specific. I will describe
what I mean.

If the warning is given because the function definition:

return_type func() { /* body */ }

...does not provide a prototype, then I think better wording would be:

That deserves no warning whatsoever. However, calling the function
earlier in the source, without having a prototype, is an error (not
a warning).
 
K

Keith Thompson

Jack Klein said:
Surely here you meant "%li", again. If you are going to check *printf
format strings and warn about mismatches, "%i" is a mismatch for long,
even on implementations where both have the same size and
implementation.
[...]

No, I'm fairly sure he meant what he wrote. Apparently lcc-win32
internally treats int and long as the same type, at least in some
ways. Given that fact, he has a choice; he can warn about both
printf("%li", long_value); /* correct */
and
printf("%i, long_value); /* incorrect */
or he can warn about neither. Of the two options, I agree that
warning about neither is better.

Of course, warning about the second and not about the first would be
ideal, but apparently that's going to take some more work.
 
I

Ian Collins

jacob said:
After a user asked for clarification about some warnings issued by
lcc-win, I have updated the compiler to reflect this discussion.

1) The buggy warning about
long l;
printf("%li", l * 10L);
is eliminated. This means that when you
write:
long l;
printf("%i", l*10L);
there will be no warning about expecting an
integer given a long. Better less warnings always correct
than more warnings sometimes incorrect. The alternative, i.e.
maintaining the type long internally when both long and int
are identical would be too much changes in the compiler.
If you treat them as the same internally, you'll be buggered when
porting to any LP64 64 bit system. That is any 64 bit Linux/Unix platform.
 
I

Ian Collins

Richard said:
Ian Collins said:

If you treat [long and int] as the same internally, you'll be buggered
when porting to any LP64 64 bit system. That is any 64 bit Linux/Unix
platform.

Ian, considering the attitude of the purported author of lcc-win32 towards,
and his knowledge of, portability, do you seriously think there is even
the remotest chance of a trouble-free port to any significantly disparate
system?
I thought he has a Linux port?
 
R

Richard Heathfield

Ian Collins said:

If you treat [long and int] as the same internally, you'll be buggered
when porting to any LP64 64 bit system. That is any 64 bit Linux/Unix
platform.

Ian, considering the attitude of the purported author of lcc-win32 towards,
and his knowledge of, portability, do you seriously think there is even
the remotest chance of a trouble-free port to any significantly disparate
system?
 
J

Jack Klein

That deserves no warning whatsoever. However, calling the function
earlier in the source, without having a prototype, is an error (not
a warning).

I disagree, I would not mind having such a warning as an _option_. I
consider it an "error" in new code (note C does not define this term),
and would turn the option off for legacy code if necessary.

As for making it an "error", presumably refusing to generate an
executable, could render the compiler non-conforming in some
situations.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://c-faq.com/
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.club.cc.cmu.edu/~ajo/docs/FAQ-acllc.html
 
R

Richard Heathfield

Ian Collins said:
Richard said:
Ian Collins said:

If you treat [long and int] as the same internally, you'll be buggered
when porting to any LP64 64 bit system. That is any 64 bit Linux/Unix
platform.

Ian, considering the attitude of the purported author of lcc-win32
towards, and his knowledge of, portability, do you seriously think there
is even the remotest chance of a trouble-free port to any significantly
disparate system?
I thought he has a Linux port?

For the benefit of the folks from Missouri, would you care to back that
statement with a URL?
 
C

CBFalconer

Jack said:
I disagree, I would not mind having such a warning as an _option_.
I consider it an "error" in new code (note C does not define this
term), and would turn the option off for legacy code if necessary.

Now why would you say that? To my mind, prototypes have just two
purposes: 1. Expose the calling sequence to other files, and 2.
Resolve indirect recursive calls. A third may exist, in order to
provide the outline of a function pointer to be passed.

Some people use them further to reorder their code, but I consider
that foolish, since the presence of a prototype requires perfect
matching with the actual definition, and the best match is attained
with no prototype (other than the definition proper). In the main
all this requires is definition before use. The presence of a
redundant prototype calls for errors at some point in time, maybe
initially, maybe years later during revisions.
 
J

jacob navia

Eric said:
Does the compiler really treat `int' and `long' as
identical? If so, what does it do with

int value = 42;
long *ptr = &value;
or with
extern long global;
extern int global;
or with
int func(void);
long func(void) { return 42L; }

? Diagnostics are required for these -- if the compiler
is able to emit them it must be "aware" at some level that
`int' and `long' are different, even though they share a
common representation.

I wrote this test program:
extern long global;
extern int global;
int func(void);
int fn(void) {
int value = 42;
long *ptr = &value;
}

long func(void) { return 42; }

At default diagnostic level lcc-win produces:

d:\lcc\test>lcc twarn.c
Error twarn.c: 2 redefinition of 'global'
Error twarn.c: 1 Previous definition of 'global' here
Warning twarn.c: 7 missing return value
Error twarn.c: 9 redefinition of 'func'
Error twarn.c: 3 Previous definition of 'func' here
4 errors, 1 warning

With extended diagnostics turned ON:
d:\lcc\mc68\test>lcc -A twarn.c
Error twarn.c: 2 redefinition of 'global'
Error twarn.c: 1 Previous definition of 'global' here
Warning twarn.c: 6 assignment of pointer to int to pointer to long int
Warning twarn.c: 6 ptr is assigned a value that is never used
Warning twarn.c: 7 missing return value
Error twarn.c: 9 redefinition of 'func'
Error twarn.c: 3 Previous definition of 'func' here
4 errors, 3 warnings

Note that lcc-win is much more strict than MSVC that
issues no errors, just warnings:

twarn.c(2) : warning C4142: benign redefinition of type
twarn.c(9) : warning C4142: benign redefinition of type
d:\lcc\test\twarn.c(7) : warning C4716: 'fn' : must return a value

-------------------------------------------------------------
In all this "easy" cases, the diagnostics are issued before
the evaluation and transformation of types is done. In the
case of printf however, the tests are done just before
the function call, well after they have been prepared to
be put in the stack, hence the problems. Of course I should
test before, but that is quite a lot of work.
 
J

jacob navia

Ian said:
Richard said:
Ian Collins said:

If you treat [long and int] as the same internally, you'll be buggered
when porting to any LP64 64 bit system. That is any 64 bit Linux/Unix
platform.
Ian, considering the attitude of the purported author of lcc-win32 towards,
and his knowledge of, portability, do you seriously think there is even
the remotest chance of a trouble-free port to any significantly disparate
system?
I thought he has a Linux port?

lcc-win has been ported to linux (32 and 64 bits) to AIX (64 bits),
and to windows 64 bits.

lcc-win generates code for some DSP 16 bits also.
 
K

Keith Thompson

CBFalconer said:
That deserves no warning whatsoever. However, calling the function
earlier in the source, without having a prototype, is an error (not
a warning).

That definition does not provide a prototype.

More concretely:

void foo()
{
}

int main(void)
{
foo(42);
return 0;
}

The definition of 'foo' does not provide a prototype. The incorrect
call 'foo(42)' is not a constraint violation, though it does invoke
undefined behavior.

On the other hand, if the definition of foo were:

void foo(void)
{
}

then the call would be a constraint violation.
 
R

Richard Heathfield

CBFalconer said:

Some people use [prototypes] further to reorder their code, but I
consider that foolish, since the presence of a prototype requires perfect
matching with the actual definition, and the best match is attained
with no prototype (other than the definition proper). In the main
all this requires is definition before use. The presence of a
redundant prototype calls for errors at some point in time, maybe
initially, maybe years later during revisions.

I disagree that using prototypes to free the code from a strict ordering is
a bad idea. Yes, okay, the presence of two got-to-match prototypes rather
than one is a weakness, but so is the reliance on a strict ordering.
Either can be broken during maintenance (and the fix for each is trivial).

If you want to use up-front prototypes to get rid of the problem of
reliance on strict ordering, without suffering the problem of two
got-to-match sections of code, I advance the following, not entirely
serious, suggestion:

#define PROTOTYPE_FOO double foo(char *x, int y)

PROTOTYPE_FOO ;

PROTOTYPE_FOO
{
/* write foo()'s body here */
}

:)
 
I

Ian Collins

jacob said:
Ian said:
Richard said:
Ian Collins said:

<snip>

If you treat [long and int] as the same internally, you'll be buggered
when porting to any LP64 64 bit system. That is any 64 bit Linux/Unix
platform.
Ian, considering the attitude of the purported author of lcc-win32
towards, and his knowledge of, portability, do you seriously think
there is even the remotest chance of a trouble-free port to any
significantly disparate system?
I thought he has a Linux port?
lcc-win has been ported to linux (32 and 64 bits) to AIX (64 bits),
and to windows 64 bits.
So you have already differentiated between int and long?
 
J

jacob navia

Ian said:
jacob said:
Ian said:
Richard Heathfield wrote:
Ian Collins said:

<snip>

If you treat [long and int] as the same internally, you'll be buggered
when porting to any LP64 64 bit system. That is any 64 bit Linux/Unix
platform.
Ian, considering the attitude of the purported author of lcc-win32
towards, and his knowledge of, portability, do you seriously think
there is even the remotest chance of a trouble-free port to any
significantly disparate system?

I thought he has a Linux port?
lcc-win has been ported to linux (32 and 64 bits) to AIX (64 bits),
and to windows 64 bits.
So you have already differentiated between int and long?

In 64 bit linux I have hacked the lexer!

When I see a "long" keyword, I return "long long". Internally
"long" is still never used. This works quite OK.

The problem with "long" is that it is always just a synonym for either
int or long long. There is no point in maintaining a basic type that
isn't really one.

Another thing would be if we had
int 32 bits
long 64 bits
long long 128 bits.

In *that* case long would be a proper type.
 
K

Keith Thompson

CBFalconer said:
Now why would you say that? To my mind, prototypes have just two
purposes: 1. Expose the calling sequence to other files, and 2.
Resolve indirect recursive calls. A third may exist, in order to
provide the outline of a function pointer to be passed.

Some people use them further to reorder their code, but I consider
that foolish, since the presence of a prototype requires perfect
matching with the actual definition, and the best match is attained
with no prototype (other than the definition proper). In the main
all this requires is definition before use. The presence of a
redundant prototype calls for errors at some point in time, maybe
initially, maybe years later during revisions.

I think you're using the word "prototype" to refer only to function
declarations that are not also definitions. But that's not what the
word means. Any function declaration that specifies the types of the
arguments is a prototype, whether it's part of a definition or not.

Even if you strictly order your functions within a single file so that
each one is defined before it's called, each function should still
have a prototype (even though the language doesn't require it). For
example, this:

void foo(void) { /* ... */ }
void bar(void) { foo(); }

rather than this:

void foo() { /* ... */ }
void bar() { foo(); }

With the latter version, calls to foo are not checked for the correct
number and type(s) of arguments, even though the definition of foo
precedes the call.
 
P

Pietro Cerutti

jacob said:
Ian said:
jacob said:
Ian Collins wrote:
Richard Heathfield wrote:
Ian Collins said:

<snip>

If you treat [long and int] as the same internally, you'll be
buggered
when porting to any LP64 64 bit system. That is any 64 bit
Linux/Unix
platform.
Ian, considering the attitude of the purported author of lcc-win32
towards, and his knowledge of, portability, do you seriously think
there is even the remotest chance of a trouble-free port to any
significantly disparate system?

I thought he has a Linux port?

lcc-win has been ported to linux (32 and 64 bits) to AIX (64 bits),
and to windows 64 bits.
So you have already differentiated between int and long?

In 64 bit linux I have hacked the lexer!

When I see a "long" keyword, I return "long long". Internally
"long" is still never used. This works quite OK.

The problem with "long" is that it is always just a synonym for either
int or long long. There is no point in maintaining a basic type that
isn't really one.

Where does this statement come from?
What prevents long to be a type by itself?
 
J

jacob navia

Keith said:
I think you're using the word "prototype" to refer only to function
declarations that are not also definitions. But that's not what the
word means. Any function declaration that specifies the types of the
arguments is a prototype, whether it's part of a definition or not.

Even if you strictly order your functions within a single file so that
each one is defined before it's called, each function should still
have a prototype (even though the language doesn't require it). For
example, this:

void foo(void) { /* ... */ }
void bar(void) { foo(); }

rather than this:

void foo() { /* ... */ }
void bar() { foo(); }

With the latter version, calls to foo are not checked for the correct
number and type(s) of arguments, even though the definition of foo
precedes the call.

I think this should go in the FAQ...

It is very important to see that with those "old style"
definitions you have no longer those checks we are used
to rely on.
 

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

Forum statistics

Threads
473,982
Messages
2,570,185
Members
46,737
Latest member
Georgeengab

Latest Threads

Top