Newbie question

L

Longfellow

I would like the opinions of the experts here, hopefully in agreement.

I've developed the bones of an application with a C backend and a Gtk
front end (NB gtk compiles with the -ansi switch and so is legitimate to
mention in this forum). I've not been able to get them to talk directly
to each other in a reliable manner, so I've set it up for them to use
the same data base to pass stuff back and forth.

What I've done is declare a struct in a header file, which is included
in the files for both ends. For example:

-------
/* --- data.h --- */
struct data {
char question[80];
char answer[80];
} calc[80];
-------

This works fine. My question is this: Is this legal and conforming?

I get from K&R2, page 82, that functions can indeed be declared in
header files. Do I understand this correctly?

Because if I do, then I'm ready to start building this application
keeping the C and the Gtk completely separate. And I sure don't want to
start this project on the basis of UB or IDB.

Thanks all,

Longfellow
 
P

pete

Longfellow wrote:
-------
/* --- data.h --- */
struct data {
char question[80];
char answer[80];
} calc[80];

Yes.
Using header guards, will prevent anything in the header file
that isn't supposed to occur twice in a c file,
like a complete struct declaration,
from occuring twice in a c file.

You should reserve a convention for the guard macro,
so that it won't be duplicated elsewhere accidentally.
Something like starting it with an H_,
and ending it with an underscore_.

-------
/* --- data.h --- */

#ifndef H_data_
#define H_data_

struct data {
char question[80];
char answer[80];
} calc[80];

#endif
-------

I get from K&R2, page 82, that functions can indeed be declared in
header files. Do I understand this correctly?

Declared in header files,
but best not to be defined there.
 
F

Flash Gordon

Longfellow said:
I would like the opinions of the experts here, hopefully in agreement.

I've developed the bones of an application with a C backend and a Gtk
front end (NB gtk compiles with the -ansi switch and so is legitimate to
mention in this forum).

Gtk is still off topic. Do you expect us to know all the libraries and
applications written in C? There are literally thousands (or more) of
them, and if we covered them all this group would be of no use because
you would not be able to find the interesting (to you) stuff amongst all
the rest. Of course, if you posted part of the Gtk source written in
standard C we could discuss it and that would be fine.

BTW, since GTK does graphics, by definition it cannot be entirely
standard C since standard C provides no mechanism for doing graphics.
> I've not been able to get them to talk directly
to each other in a reliable manner, so I've set it up for them to use
the same data base to pass stuff back and forth.

Sounds to me like you don't know how to use GTK properly, but discussing
that belongs on a GTK mailing list probably.
What I've done is declare a struct in a header file, which is included
in the files for both ends. For example:

Declaring structs, typedefs, function prototypes etc yes, defining
objects and function no.
-------
/* --- data.h --- */
struct data {
char question[80];
char answer[80];
} calc[80];
-------

Here you are not merely defining the struct, you are also defining an
object called calc which is an array of structs.
This works fine. My question is this: Is this legal and conforming?

No, absolutely not. Any object that you use must be defined EXACTLY
once, and because data.h is included in more than one source file any
objects it defines are defined multiple times.

You want something like:
/* --- data.h --- */
#define CALC_SIZE 80

struct data {
char question[80];
char answer[80];
};
extern struct data calc[CALC_SIZE];

Then, in EXACTLY one C source file (not header) which includes data.h
you have
struct data calc[CALC_SIZE];
I get from K&R2, page 82, that functions can indeed be declared in
header files. Do I understand this correctly?

Yes, but only if you understand the difference between a declaration
(which says basically this thing exists somewhere, but I'm not defining
it here) and a definition (which says OK, this is the actual
object/function right here so allocate the space/put the code here).

You need to read up on these topics, look up declaration and definition
in K&R2 and learn what the two terms mean before you go any further.
Because if I do, then I'm ready to start building this application
keeping the C and the Gtk completely separate.

Yes, keeping your system dependant code (in this case code dealing with
GTK) isolated is a good idea.
> And I sure don't want to
start this project on the basis of UB or IDB.

This is also a good idea, and certainly something we can help with.
 
P

pete

pete said:
-------
/* --- data.h --- */
struct data {
char question[80];
char answer[80];
} calc[80];

Yes.

I should have said "No".
I didn't notice until after reading Flash Gordon's reply
that that was an object defintion
and not just a struct declaration.
 
F

Flash Gordon

pete said:
Longfellow said:
-------
/* --- data.h --- */
struct data {
char question[80];
char answer[80];
} calc[80];

Yes.
Using header guards, will prevent anything in the header file
that isn't supposed to occur twice in a c file,
like a complete struct declaration,
from occuring twice in a c file.

You seem to have failed to spot that Longfellow is also defining a
variable, and header guards won't help prevent the undefined behaviour
that therefore results when two separate c files include that header.
You should reserve a convention for the guard macro,
so that it won't be duplicated elsewhere accidentally.
Something like starting it with an H_,
and ending it with an underscore_.

-------
/* --- data.h --- */

#ifndef H_data_
#define H_data_

struct data {
char question[80];
char answer[80];
} calc[80];

Here you have repeated the error of defining a variable as well as the
structure in the header file.
#endif
-------



Declared in header files,
but best not to be defined there.

Same for variables, such as calc in the above code.
 
L

Longfellow

<snip>

Thanks, I shall study on this reply. I now have a better idea of what I
should be looking for in terms of standards definitions.

Longfellow
 
L

Longfellow

After further review:

Longfellow wrote:
What I've done is declare a struct in a header file, which is included
in the files for both ends. For example:

Declaring structs, typedefs, function prototypes etc yes, defining
objects and function no.
-------
/* --- data.h --- */
struct data {
char question[80];
char answer[80];
} calc[80];
-------

Here you are not merely defining the struct, you are also defining an
object called calc which is an array of structs.

Not defining, just initializing. This declaration is made only once in
the header file and not again referenced in the code. It is assumed
that every file that has that header included should know what it needs
to know about that array of structs.
No, absolutely not. Any object that you use must be defined EXACTLY
once, and because data.h is included in more than one source file any
objects it defines are defined multiple times.

Prohibition is against declaring an object more than once, I think. H&S
says on page 79 that one of the two exceptions to this rule is when an
object is declared as the same type every time, as in a header file that
can be shared with all code files. You are correct that an inclusion of
the header file in each code file is a duplicate declaration, but this
exception exists because otherwise the standard C library would be
illegal.
You want something like:
/* --- data.h --- */
#define CALC_SIZE 80

struct data {
char question[80];
char answer[80];
};
extern struct data calc[CALC_SIZE];

This does not compile.
Then, in EXACTLY one C source file (not header) which includes data.h
you have
struct data calc[CALC_SIZE];

See above.
Yes, but only if you understand the difference between a declaration
(which says basically this thing exists somewhere, but I'm not defining
it here) and a definition (which says OK, this is the actual
object/function right here so allocate the space/put the code here).

Apparently an initialized declaration at the top level is considered a
legal defining declaration [H&S pp113-116].

For my purposes, having this array of structs globally available via a
header file serves my purpose. Where I don't need it, the header file
will not be included, and I'm going to make the variable names unique
enough so that they will not be duplicated elsewhere.

In any case, it compiles cleanly with -Wall -ansi -pedantic. I've no
idea how this setup will fare as I flesh it all out, but I think I'll
drag out lclint and use it continuously. That way, I'll know that I'm
staying out of trouble.

Thanks anyway,

Longfellow
 
B

Barry Schwarz

After further review:

Longfellow wrote:
What I've done is declare a struct in a header file, which is included
in the files for both ends. For example:

Declaring structs, typedefs, function prototypes etc yes, defining
objects and function no.
-------
/* --- data.h --- */
struct data {
char question[80];
char answer[80];
} calc[80];
-------

Here you are not merely defining the struct, you are also defining an
object called calc which is an array of structs.

Not defining, just initializing. This declaration is made only once in
the header file and not again referenced in the code. It is assumed
that every file that has that header included should know what it needs
to know about that array of structs.

No, this is a definition. If you include your header before any
functions, the array calc will be defined with external linkage. If
the header is included in two different translation units, your linker
will complain about duplicates.
No, absolutely not. Any object that you use must be defined EXACTLY
once, and because data.h is included in more than one source file any
objects it defines are defined multiple times.

Prohibition is against declaring an object more than once, I think. H&S
says on page 79 that one of the two exceptions to this rule is when an
object is declared as the same type every time, as in a header file that
can be shared with all code files. You are correct that an inclusion of
the header file in each code file is a duplicate declaration, but this
exception exists because otherwise the standard C library would be
illegal.
You want something like:
/* --- data.h --- */
#define CALC_SIZE 80

struct data {
char question[80];
char answer[80];
};
extern struct data calc[CALC_SIZE];

This does not compile.
Then, in EXACTLY one C source file (not header) which includes data.h
you have
struct data calc[CALC_SIZE];

See above.
Yes, but only if you understand the difference between a declaration
(which says basically this thing exists somewhere, but I'm not defining
it here) and a definition (which says OK, this is the actual
object/function right here so allocate the space/put the code here).

Apparently an initialized declaration at the top level is considered a
legal defining declaration [H&S pp113-116].

For my purposes, having this array of structs globally available via a
header file serves my purpose. Where I don't need it, the header file
will not be included, and I'm going to make the variable names unique
enough so that they will not be duplicated elsewhere.

In any case, it compiles cleanly with -Wall -ansi -pedantic. I've no
idea how this setup will fare as I flesh it all out, but I think I'll
drag out lclint and use it continuously. That way, I'll know that I'm
staying out of trouble.

Thanks anyway,

Longfellow


<<Remove the del for email>>
 
F

Flash Gordon

Longfellow said:
After further review:

Longfellow wrote:
What I've done is declare a struct in a header file, which is included
in the files for both ends. For example:
Declaring structs, typedefs, function prototypes etc yes, defining
objects and function no.
-------
/* --- data.h --- */
struct data {
char question[80];
char answer[80];
} calc[80];
-------
Here you are not merely defining the struct, you are also defining an
object called calc which is an array of structs.

Not defining, just initializing.

No, it is NOT initialising, it is defining.
> This declaration is made only once in
the header file and not again referenced in the code.

It IS a definition of calc.
> It is assumed
that every file that has that header included should know what it needs
to know about that array of structs.

That is true, and that is the reason for providing an extern declaration.
Prohibition is against declaring an object more than once, I think.

It is, and by including the above header in more than one translation
unit that is *exactly* what you are doing.
> H&S
says on page 79 that one of the two exceptions to this rule is when an
object is declared as the same type every time, as in a header file that
can be shared with all code files.

You can declare an object (with the same time, or an incomplete
declaration that is compatible) as often as you want, but that is NOT
what the header does, the header defines the object.
> You are correct that an inclusion of
the header file in each code file is a duplicate declaration,

No, it is a definition, not a declaration.
> but this
exception exists because otherwise the standard C library would be
illegal.

No, because the standard headers declares, they do not define.

Note that for functions you don't need the extern keyword to provide
declarations (but you can), but with object types you do.
You want something like:
/* --- data.h --- */
#define CALC_SIZE 80

struct data {
char question[80];
char answer[80];
};
extern struct data calc[CALC_SIZE];

This does not compile.

It compiles perfectly when I try it. Have you put it through a compiler
and what error do you get?
Then, in EXACTLY one C source file (not header) which includes data.h
you have
struct data calc[CALC_SIZE];

See above.

Incorrect. It compiles perfectly cleanly. I just pasted it in to a C
file I had, so I know this to be true.
Yes, but only if you understand the difference between a declaration
(which says basically this thing exists somewhere, but I'm not defining
it here) and a definition (which says OK, this is the actual
object/function right here so allocate the space/put the code here).

Apparently an initialized declaration at the top level is considered a
legal defining declaration [H&S pp113-116].

There is no such thing as a "initialised declaration" in C. There are
declarations, definitions, and definitions with initialisers. What you
provided was a definition, what I provided was a declaration. I don't
have H&S so I can't comment on what it says, but either it is wrong or
you are misunderstanding it.
For my purposes, having this array of structs globally available via a
header file serves my purpose. Where I don't need it, the header file
will not be included, and I'm going to make the variable names unique
enough so that they will not be duplicated elsewhere.

It should be declared in the header and defined in exactly one C file.
Exactly as I stated.
In any case, it compiles cleanly with -Wall -ansi -pedantic.

As does what I provided, however those options do *NOT* generate a
diagnostic for multiple definitions.

<OT>
If you want gcc to catch your error, and your version supports it,
compile *all* of your code with the -fno-common option and it will then
generate an error at link time.
> I've no
idea how this setup will fare as I flesh it all out, but I think I'll
drag out lclint and use it continuously. That way, I'll know that I'm
staying out of trouble.

Without fixing the *serious* problem I have tried to tell you about it
may well work today with your current options, but it will *not* work in
all environments.
 
P

pete

Flash said:
Longfellow said:
-------
/* --- data.h --- */
struct data {
char question[80];
char answer[80];
} calc[80];

Yes.
Using header guards, will prevent anything in the header file
that isn't supposed to occur twice in a c file,
like a complete struct declaration,
from occuring twice in a c file.

You seem to have failed to spot that Longfellow is also defining a
variable, and header guards won't help prevent the undefined behaviour
that therefore results when two separate c files include that header.
You should reserve a convention for the guard macro,
so that it won't be duplicated elsewhere accidentally.
Something like starting it with an H_,
and ending it with an underscore_.

-------
/* --- data.h --- */

#ifndef H_data_
#define H_data_

struct data {
char question[80];
char answer[80];
} calc[80];

Here you have repeated the error of defining a variable as well as the
structure in the header file.
#endif
-------



Declared in header files,
but best not to be defined there.

Same for variables, such as calc in the above code.

Yup. :(
 

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,172
Messages
2,570,934
Members
47,473
Latest member
ChristelPe

Latest Threads

Top