Question about a splint diagnostic

S

spibou

I have two identical files , u1.c and u2.c which only contain
the line
typedef int Q ;
When I issue "splint u1.c u2.c" I get

u2.c:1:13: Datatype Q defined more than once
A function or variable is redefined. One of the declarations should
use
extern. (Use -redef to inhibit warning)
u1.c:1:13: Previous definition of Q

Finished checking --- 1 code warning

Is this warning justified ? I thought that typedef's have file scope.

Spiros Bousbouras
 
J

jacob navia

(e-mail address removed) a écrit :
I have two identical files , u1.c and u2.c which only contain
the line
typedef int Q ;
When I issue "splint u1.c u2.c" I get

u2.c:1:13: Datatype Q defined more than once
A function or variable is redefined. One of the declarations should
use
extern. (Use -redef to inhibit warning)
u1.c:1:13: Previous definition of Q

Finished checking --- 1 code warning

Is this warning justified ? I thought that typedef's have file scope.

Spiros Bousbouras

typedef's have compilation unit scope, OK. BUT
splint flags this as an error very probably because
TWO definitions of the same type are a disaster
waiting to happen...

It is very difficult to remember which is which
if they are different, and it is a bad practice.

This is of course my opinion only.

jacob
 
S

spibou

jacob said:
(e-mail address removed) a écrit :

typedef's have compilation unit scope, OK. BUT
splint flags this as an error very probably because
TWO definitions of the same type are a disaster
waiting to happen...

It is very difficult to remember which is which
if they are different, and it is a bad practice.

How should I write it to avoid the warning ? Following splint's
advice I tried
typedef extern int Q ;
in the file u2.c splint is ok with that but lint gives

(1) error: only one storage class allowed
lint: errors in u2.c; no output created
lint: pass2 not run - errors in u2.c

The motto "you can't please everyone" seems to be
true for code checking utilities too !

Let me explain how I first encountered the problem.
I was writing a function in its own file ; let's call
it foo.c The file included a typedef. Then I wrote
a short testing programme , test.c The test programme
needed of course the same datatype so I put an identical
typedef inside test.c It compiles fine but as an extra
precaution I also put it through splint and that's when
I got the warning about the same datatype being defined
more than once.

This function will be part of my own library and I plan
to use it with more than one programmes. The headers of
standard library functions do not contain "extern" next
to typedef and one does not get any warnings. I take it
that this happens because one only links with the libraries
rather than compiling them with one's own programme. But
with my own libraries I tend to go for the simpler option
and just write
cc my-programme.c my-library.c
rather than create a linkable object file from my-library.c
Off the top of my head I don't even know how to do that.
So if I compile with
cc my-programme.c my-library.c
I also want to write
splint my-programme.c my-library.c
and get as little warnings as possible. As far as I can see
I have 2 options:
1) Continue to write splint my-programme.c my-library.c
and accept that I will get warnings when my-programme.c
duplicates the typedef's from my-library.c
2) Create linkable object files for my libraries and only
link with those.

Is there another option that I'm missing ?

Spiros Bousbouras
 
J

jacob navia

(e-mail address removed) a écrit :
jacob navia wrote:




How should I write it to avoid the warning ? Following splint's
advice I tried
typedef extern int Q ;
in the file u2.c splint is ok with that but lint gives

(1) error: only one storage class allowed
lint: errors in u2.c; no output created
lint: pass2 not run - errors in u2.c

The motto "you can't please everyone" seems to be
true for code checking utilities too !

Let me explain how I first encountered the problem.
I was writing a function in its own file ; let's call
it foo.c The file included a typedef. Then I wrote
a short testing programme , test.c The test programme
needed of course the same datatype so I put an identical
typedef inside test.c It compiles fine but as an extra
precaution I also put it through splint and that's when
I got the warning about the same datatype being defined
more than once.

This function will be part of my own library and I plan
to use it with more than one programmes. The headers of
standard library functions do not contain "extern" next
to typedef and one does not get any warnings. I take it
that this happens because one only links with the libraries
rather than compiling them with one's own programme. But
with my own libraries I tend to go for the simpler option
and just write
cc my-programme.c my-library.c
rather than create a linkable object file from my-library.c
Off the top of my head I don't even know how to do that.
So if I compile with
cc my-programme.c my-library.c
I also want to write
splint my-programme.c my-library.c
and get as little warnings as possible. As far as I can see
I have 2 options:
1) Continue to write splint my-programme.c my-library.c
and accept that I will get warnings when my-programme.c
duplicates the typedef's from my-library.c
2) Create linkable object files for my libraries and only
link with those.

Is there another option that I'm missing ?

Spiros Bousbouras

Normally you put your typedefs in a common header file like
u2.h

Then, both files
#include "u2.h"

and you have the same effect, with only ONE definition.

jacob
 
S

spibou

jacob said:
Normally you put your typedefs in a common header file like
u2.h

Then, both files
#include "u2.h"

and you have the same effect, with only ONE definition.

jacob

But then the typedef will appear in both files and I will have
two (identical) definitions. I'm using identical definitions
now and I get the warning.
 
S

Skarmander

But then the typedef will appear in both files and I will have
two (identical) definitions. I'm using identical definitions
now and I get the warning.
Have you actually tried it? This is so common that splint ought to detect it
and not warn about it. To the compiler, it's the same thing; to splint it
may not be.

S.
 
S

spibou

Skarmander said:
Have you actually tried it? This is so common that splint ought to detect it
and not warn about it. To the compiler, it's the same thing; to splint it
may not be.

It works ! Thanks.
 
C

Chris Torek

I have two identical files , u1.c and u2.c which only contain
the line
typedef int Q ;
When I issue "splint u1.c u2.c" I get

u2.c:1:13: Datatype Q defined more than once
A function or variable is redefined. One of the declarations should use
extern. (Use -redef to inhibit warning)
u1.c:1:13: Previous definition of Q

Finished checking --- 1 code warning

Is this warning justified ? I thought that typedef's have file scope.

A "typedef" has the same scope as any ordinary declaration: if
it appears inside a function, for instance, it has block scope.
A typedef at file scope thus has file scope (as you noted).

It seems likely that splint is complaining because the typedef is
in different *source files*, rather than different translation
units. That is, splint is tracing the "typedef" line to a specific
file, and if multiple compilation units get the same typename from
*separate* files, it gripes. This is presumably to prevent you
from doing something like this:

% cat foo.h
Temperature measure(void);
% cat foo.c
typedef int Temperature;
#include "foo.h"
Temperature measure(void) { return 42; }
% cat main.c
typedef double Temperature;
#include "foo.h"
int main(void) {
printf("it's %f degrees\n", measure());
return 0;
}

These code fragments will most likely compile, yet when run, will
produce nonsense: main.c believes that measure() returns a double,
while foo.c's measure() actually returns an "int". The header
foo.h is shared between foo.c and main.c, but refers to a typedef
that is defined *differently* in the two .c files. If the typedef
line were also in the .h file, it would be impossible to get it
wrong in one of the .c files.

As for the "explanation" below the warning, it is just wrong. The
"extern" keyword is a storage-class-specifier, as is the typedef
keyword (even though the latter is an s-c-specifier purely for
syntactic reasons), and only one s-c-specifier keyword is allowed
in any declaration. (Probably splint has just one command line
option -- "-redef" -- that affects both ordinary, non-"typedef"
identifiers -- where you *can* use extern -- and "typedef" identifiers,
where you cannot.)
 
K

Keith Thompson

I have two identical files , u1.c and u2.c which only contain
the line
typedef int Q ;
When I issue "splint u1.c u2.c" I get

u2.c:1:13: Datatype Q defined more than once
A function or variable is redefined. One of the declarations should
use
extern. (Use -redef to inhibit warning)
u1.c:1:13: Previous definition of Q

Finished checking --- 1 code warning

Is this warning justified ? I thought that typedef's have file scope.

Having typedefs with the same name in two different *.c files is ok.

Typically you would invoke the compiler separately for each *.c file.
For example, you might do something like:

gcc -c u1.c
gcc -c u2.c
gcc u1.o u2.o -o main_program

but the manner in which you invoke the compiler to compile multiple
source files is implementation-specific. I see that "gcc u1.c u2.c"
does work, but that doesn't guarantee that "splint u1.c u2.c" will
mean the same thing.

The documentation for splint would likely be instructive.

As a matter of program design, having the same typedef (assuming it's
intended to be the same) in two separate source files is a bad idea,
even if it's legal. Put it in a header file included by both .c
files, with include guards so the compiler sees the typedef only once
per translation unit.

<OT>
For a large project, you should probably use some system that figures
out how to invoke the compiler for you, such as a Makefile or an IDE.
This would probably invoke the compiler once for each .c file; you
should probably invokes splint the same way, possibly under control of
your Makefile.
</OT>
 
S

spibou

Keith said:
The documentation for splint would likely be instructive.

As a matter of program design, having the same typedef (assuming it's
intended to be the same) in two separate source files is a bad idea,
even if it's legal. Put it in a header file included by both .c
files, with include guards so the compiler sees the typedef only once
per translation unit.

<OT>
For a large project, you should probably use some system that figures
out how to invoke the compiler for you, such as a Makefile or an IDE.
This would probably invoke the compiler once for each .c file; you
should probably invokes splint the same way, possibly under control of
your Makefile.
</OT>

out_of_topic {
I just did a quick experiment with splint. I used it
on a source file without main and it didn't produce
any sort of "object" file so I think that in order to
detect various discrepancies between different source
files it needs to be invoked with all the files together.

I do need to read the manual eventually.
}

By the way why is advice on how to handle large projects in C
out of topic ?

Spiros Bousbouras
 
R

Richard Heathfield

(e-mail address removed) said:

By the way why is advice on how to handle large projects in C
out of topic ?

The C part of it isn't, but the C part is not difficult, and does not lend
itself to particularly involved discussions. In fact, it can be described
in about three words - "do it properly". :)
 
K

Keith Thompson

out_of_topic {
I just did a quick experiment with splint. I used it
on a source file without main and it didn't produce
any sort of "object" file so I think that in order to
detect various discrepancies between different source
files it needs to be invoked with all the files together.

Of course it didn't produce an object file. It's a static source code
checker; that's not its job. If by "object" file you meant something
that splint can use to do checking across translation units, that's a
good point; if splint doesn't do that, either it can't do cross-unit
checks or it uses some other method to do them. You'll undoubtedly
find that information in the splint manual.

Quite possibly it's going to warn about things that are perfectly
legal. In your original example, you had the same typedef in two
different translation units. This is quite legal, but it could be a
maintenance headache; if you change it, you'll have to make sure it
remains consistent across all the multiple definitions. Perhaps this
is what splint is warning you about. As we've mentioned, writing the
typedef exactly once in a header is a much better approach.
I do need to read the manual eventually.
Yep.

}

By the way why is advice on how to handle large projects in C
out of topic ?

Because the C standard doesn't provide a way to do it. Even how a
compiler is invoked is outside the scope of the language; different
compilers are invoked in different ways. Makefiles, for example, are
one way to manage large projects -- and there are a number of tools
built on top of that, tools that generate Makefiles from some even
higher-level description. All these tools are system-specific.
 
H

Herbert Rosenau

out_of_topic {
I just did a quick experiment with splint. I used it
on a source file without main and it didn't produce
any sort of "object" file so I think that in order to
detect various discrepancies between different source
files it needs to be invoked with all the files together.

It is NOT the job of splint to produce object files. Its job is "only"
to check the source for errors and complain against them.
I do need to read the manual eventually.
}

By the way why is advice on how to handle large projects in C
out of topic ?

There is no standard defined
- how to invoke a compiler
- how to invoke a linker
- how to invoke another tools (like make)
- how to get multiple source files bounded to an executeable

As this group is only to handle C in a compatible way you has to ask
in a group relevant to your OS, your specific compiler, your specific
linker, your specific tool you use to come from different sources to a
single executeable. The ways to get it are so incomatible and
different that there is simple no common possibility.

The standard describes exactly how to write C in an compatible way
each and any compiler has to translate fine - but how to get from the
output a compiler produces when it has to compile multiple translation
units to get them bouned to a single executeable are at least system
specific or a bit harder specific to a specific compiler.

--
Tschau/Bye
Herbert

Visit http://www.ecomstation.de the home of german eComStation
eComStation 1.2 Deutsch ist da!
 

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,767
Messages
2,569,570
Members
45,045
Latest member
DRCM

Latest Threads

Top