A scope problem??

A

Andy

Hello Fellows,

When I compiled my source code using make. It dumped out these error
msgs:

-------------------------------------------------------------------------------------------
gcc -O2 -g -Wall -fmessage-length=0 -c -o loadgraph.o loadgraph.c
gcc -O2 -g -Wall -fmessage-length=0 -c -o lib.o lib.c
gcc -O2 -g -Wall -fmessage-length=0 -c -o hashtbl.o hashtbl.c
gcc -O2 -g -Wall -fmessage-length=0 -c -o search.o search.c
gcc -O2 -g -Wall -fmessage-length=0 -c -o strhash.o strhash.c
gcc -O2 -g -Wall -fmessage-length=0 -c -o shingle.o shingle.c
In file included from heap.h:10,
from lib.h:12,
from shingle.h:12,
from shingle.c:1:
loadgraph.h:24: error: expected '=', ',', ';', 'asm' or
'__attribute__' before '*' token
make: *** [shingle.o] Error 1
-------------------------------------------------------------------------------------------

---------------------------------------<loadgraph.h>
......
23 extern char **n2gidHash;
24 extern SGL *gFSgl;
25 extern int gN;
26 extern int gC;
---------------------------------------

I guess it should be scope problem, but I have no clue.... I had this
kind of problem before. All I did is moving the functions around, then
it worked.

I am wondering where should I start to debug this kind of problem?
Thanks in advance!

~Andy .W
 
N

Nate Eldredge

Andy said:
Hello Fellows,

When I compiled my source code using make. It dumped out these error
msgs:

-------------------------------------------------------------------------------------------
gcc -O2 -g -Wall -fmessage-length=0 -c -o loadgraph.o loadgraph.c
gcc -O2 -g -Wall -fmessage-length=0 -c -o lib.o lib.c
gcc -O2 -g -Wall -fmessage-length=0 -c -o hashtbl.o hashtbl.c
gcc -O2 -g -Wall -fmessage-length=0 -c -o search.o search.c
gcc -O2 -g -Wall -fmessage-length=0 -c -o strhash.o strhash.c
gcc -O2 -g -Wall -fmessage-length=0 -c -o shingle.o shingle.c
In file included from heap.h:10,
from lib.h:12,
from shingle.h:12,
from shingle.c:1:
loadgraph.h:24: error: expected '=', ',', ';', 'asm' or
'__attribute__' before '*' token
make: *** [shingle.o] Error 1
-------------------------------------------------------------------------------------------

---------------------------------------<loadgraph.h>
.....
23 extern char **n2gidHash;
24 extern SGL *gFSgl;
25 extern int gN;
26 extern int gC;
---------------------------------------

I guess it should be scope problem, but I have no clue.... I had this
kind of problem before. All I did is moving the functions around, then
it worked.

I am wondering where should I start to debug this kind of problem?
Thanks in advance!

The type `SGL' is probably not getting defined. Make sure the header
with the appropriate typedef is being included.
 
A

Andy

Andy said:
Hello Fellows,
When I compiled my source code using make. It dumped out these error
msgs:
-------------------------------------------------------------------------------------------
gcc -O2 -g -Wall -fmessage-length=0   -c -o loadgraph.o loadgraph.c
gcc -O2 -g -Wall -fmessage-length=0   -c -o lib.o lib.c
gcc -O2 -g -Wall -fmessage-length=0   -c -o hashtbl.o hashtbl.c
gcc -O2 -g -Wall -fmessage-length=0   -c -o search.o search.c
gcc -O2 -g -Wall -fmessage-length=0   -c -o strhash.o strhash.c
gcc -O2 -g -Wall -fmessage-length=0   -c -o shingle.o shingle.c
In file included from heap.h:10,
                 from lib.h:12,
                 from shingle.h:12,
                 from shingle.c:1:
loadgraph.h:24: error: expected '=', ',', ';', 'asm' or
'__attribute__' before '*' token
make: *** [shingle.o] Error 1
-------------------------------------------------------------------------------------------
---------------------------------------<loadgraph.h>
.....
 23 extern char **n2gidHash;
 24 extern SGL *gFSgl;
 25 extern int gN;
 26 extern int gC;
---------------------------------------
I guess it should be scope problem, but I have no clue.... I had this
kind of problem before. All I did is moving the functions around, then
it worked.
I am wondering where should I start to debug this kind of problem?
Thanks in advance!

The type `SGL' is probably not getting defined.  Make sure the header
with the appropriate typedef is being included.

Thanks!.
-----------------------------------------------------<heap.h>
1 #ifndef HEAP_H_
2 #define HEAP_H_
3
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <assert.h>
7
8 #include "type.h"
9 #include "lib.h"
10
11 #define DELETED -1
12
13 typedef struct node{
14 int vid;
15 int degree;
16 }NODE;

....
#endif
-----------------------------------------------------<heap.h>

-----------------------------------------------------<loadgraph.h>
1 #ifndef LOAD_GRAPH_H_
2 #define LOAD_GRAPH_H_
3
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <assert.h>
8
9 #include "hashtbl.h"
10 #include "shingle.h"
11 #include "heap.h"
12 #include "loadgraph.h"
13
14 /* syntax: #define name (var name) arbitrary text */
15 #define HEAD_DEL ":"
16 #define LIST_DEL ";"
17 #define MAX_GID_LEN 40
18
19
20 #define PRUNED -1
21 #define ADJ_END -2
22
23 extern char **n2gidHash;
24 extern SGL *gFSgl;
25 extern int gN;
26 extern int gC;
27 extern int gS;


....
#endif

-----------------------------------------------------<loadgraph.h>

So, SGL is defined....
 
A

Andy

Andy said:
Hello Fellows,
When I compiled my source code using make. It dumped out these error
msgs:
-------------------------------------------------------------------------------------------
gcc -O2 -g -Wall -fmessage-length=0   -c -o loadgraph.o loadgraph.c
gcc -O2 -g -Wall -fmessage-length=0   -c -o lib.o lib.c
gcc -O2 -g -Wall -fmessage-length=0   -c -o hashtbl.o hashtbl.c
gcc -O2 -g -Wall -fmessage-length=0   -c -o search.o search.c
gcc -O2 -g -Wall -fmessage-length=0   -c -o strhash.o strhash.c
gcc -O2 -g -Wall -fmessage-length=0   -c -o shingle.o shingle.c
In file included from heap.h:10,
                 from lib.h:12,
                 from shingle.h:12,
                 from shingle.c:1:
loadgraph.h:24: error: expected '=', ',', ';', 'asm' or
'__attribute__' before '*' token
make: *** [shingle.o] Error 1
-------------------------------------------------------------------------------------------
---------------------------------------<loadgraph.h>
.....
 23 extern char **n2gidHash;
 24 extern SGL *gFSgl;
 25 extern int gN;
 26 extern int gC;
---------------------------------------
I guess it should be scope problem, but I have no clue.... I had this
kind of problem before. All I did is moving the functions around, then
it worked.
I am wondering where should I start to debug this kind of problem?
Thanks in advance!

The type `SGL' is probably not getting defined.  Make sure the header
with the appropriate typedef is being included.

Thanks!

-------------------------------------------------------------------
<shingle.h>
1 #ifndef SHINGLE_H_
2 #define SHINGLE_H_
3
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <assert.h>
8 #include <limits.h>
9 #include <math.h>
10
11 #include "type.h"
12 #include "lib.h"
13 #include "search.h"
14 #include "strhash.h"
15
16 #define RADIX_BASE 11
17
18 typedef struct sgl{
19 ulong node;
20 ulong sVal;
21 int *vids;
22 }SGL;
....

#endif
-------------------------------------------------------------------
<shingle.h>

-------------------------------------------------------------------
<loadgraph.h>
1 #ifndef LOAD_GRAPH_H_
2 #define LOAD_GRAPH_H_
3
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <assert.h>
8
9 #include "hashtbl.h"
10 #include "shingle.h"
11 #include "heap.h"
12 #include "loadgraph.h"
13
14 /* syntax: #define name (var name) arbitrary text */
15 #define HEAD_DEL ":"
16 #define LIST_DEL ";"
17 #define MAX_GID_LEN 40
18
19
20 #define PRUNED -1
21 #define ADJ_END -2
22
23 extern char **n2gidHash;
24 extern SGL *gFSgl;

....
#endif
-------------------------------------------------------------------
<loadgraph.h>

I guess it should be problems in other places, because if I move
functions around. It will compile... Just wondering why? No clue...

~A.W.
 
K

Keith Thompson

Andy said:
Thanks!.
-----------------------------------------------------<heap.h>
1 #ifndef HEAP_H_
2 #define HEAP_H_
3
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <assert.h>
7
8 #include "type.h"
9 #include "lib.h"
10
11 #define DELETED -1
12
13 typedef struct node{
14 int vid;
15 int degree;
16 }NODE;

...
#endif
-----------------------------------------------------<heap.h>

-----------------------------------------------------<loadgraph.h>
1 #ifndef LOAD_GRAPH_H_
2 #define LOAD_GRAPH_H_
3
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <assert.h>
8
9 #include "hashtbl.h"
10 #include "shingle.h"
11 #include "heap.h"
12 #include "loadgraph.h"
13
14 /* syntax: #define name (var name) arbitrary text */
15 #define HEAD_DEL ":"
16 #define LIST_DEL ";"
17 #define MAX_GID_LEN 40
18
19
20 #define PRUNED -1
21 #define ADJ_END -2
22
23 extern char **n2gidHash;
24 extern SGL *gFSgl;
25 extern int gN;
26 extern int gC;
27 extern int gS;


...
#endif

-----------------------------------------------------<loadgraph.h>

So, SGL is defined....

So you say, but you haven't demonstrated it. The first occurrence of
"SGL" in the above code is in the declaration "extern SGL *gFSgl;".

Perhaps you're assuming that SGL is defined in one of the headers you
haven't shown us -- but if it were, you probably wouldn't be getting
the error message you reported upthread.

Could it be that SGL is defined as a struct rather than as a typedef?
For example, if you have:

struct SGL {
/* ... */
};

then the name SGL isn't recognized unless it follows the "struct"
keyword. If that's the case, then you could declare:

extern struct SGL *gFSgl;

A side point: You should add parenthese to some of your macro
definitions. In heap.h:

#define DELETED (-1)

In loadgraph.h:

#define PRUNED (-1)
#define ADJ_END (-2)

Without the parentheses, DELETED, for example, expands to a sequence
of two tokens, ``-'' and ``1''; depending on the context, that might
not necessarily be a unary minus applied to the constant 1.

Also, line numbers are generally a bad idea. They make it difficult
for us to grab a copy of your code and try it ourselves. You can add
a comment on a specific line, such as:

extern SGL *gFSgl; /* line 24 */

Then again you haven't shown us enough code so that we'd be able to
compile it anyway.
 
A

Andy

So you say, but you haven't demonstrated it.  The first occurrence of
"SGL" in the above code is in the declaration "extern SGL *gFSgl;".

Perhaps you're assuming that SGL is defined in one of the headers you
haven't shown us -- but if it were, you probably wouldn't be getting
the error message you reported upthread.

Could it be that SGL is defined as a struct rather than as a typedef?
For example, if you have:

    struct SGL {
        /* ... */
    };

then the name SGL isn't recognized unless it follows the "struct"
keyword.  If that's the case, then you could declare:

    extern struct SGL *gFSgl;

A side point: You should add parenthese to some of your macro
definitions.  In heap.h:

    #define DELETED (-1)

In loadgraph.h:

    #define PRUNED (-1)
    #define ADJ_END (-2)

Without the parentheses, DELETED, for example, expands to a sequence
of two tokens, ``-'' and ``1''; depending on the context, that might
not necessarily be a unary minus applied to the constant 1.

Also, line numbers are generally a bad idea.  They make it difficult
for us to grab a copy of your code and try it ourselves.  You can add
a comment on a specific line, such as:

    extern SGL *gFSgl; /* line 24 */

Then again you haven't shown us enough code so that we'd be able to
compile it anyway.

--
Keith Thompson (The_Other_Keith) (e-mail address removed)  <http://www.ghoti.net/~kst>
Nokia
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"

Thanks guys.

I figured out the reason why I made such kind of mistake. Basically it
is a bad practice of writing code.

Usually, I put the type definitions in header files, and then if some
other files want to use these type definitions, I just use the
#include. In this way, the files using these type definition may be
included before the real type definition. So it will give you some
weird error msgs...

A good way (at least I think) to debug this error is to use "gcc -E
*.c", then you can check the preprocessing file very easily:)

For instance,
----A.h-----
#ifndef A_H_
#define A_H_

#include "C.h"

typedef struct{
int x;
int y;
}NODE;

void bar();
#endif

----A.c----
#include "A.h"

void bar(){
foo();
}

----C.h------
#ifndef C_H_
#define C_H_

#include "A.h"

Node foo(); /* need to use type NODE defined in A.h */

#endif

----C.c----
#include "C.h"

Node foo(){}


----main.c----
#include "A.h"
int main(){
bar();
return 1;
}


if you try to compile this code, you will get error msgs like:
-----------------------------------
gcc -O2 -g -Wall -fmessage-length=0 -c -o main.o main.c
In file included from A.h:6,
from main.c:3:
C.h:6: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before
‘foo’
make: *** [main.o] Error 1
 
A

Andy

So you say, but you haven't demonstrated it.  The first occurrence of
"SGL" in the above code is in the declaration "extern SGL *gFSgl;".
Perhaps you're assuming that SGL is defined in one of the headers you
haven't shown us -- but if it were, you probably wouldn't be getting
the error message you reported upthread.
Could it be that SGL is defined as a struct rather than as a typedef?
For example, if you have:
    struct SGL {
        /* ... */
    };
then the name SGL isn't recognized unless it follows the "struct"
keyword.  If that's the case, then you could declare:
    extern struct SGL *gFSgl;
A side point: You should add parenthese to some of your macro
definitions.  In heap.h:
    #define DELETED (-1)
In loadgraph.h:
    #define PRUNED (-1)
    #define ADJ_END (-2)
Without the parentheses, DELETED, for example, expands to a sequence
of two tokens, ``-'' and ``1''; depending on the context, that might
not necessarily be a unary minus applied to the constant 1.
Also, line numbers are generally a bad idea.  They make it difficult
for us to grab a copy of your code and try it ourselves.  You can add
a comment on a specific line, such as:
    extern SGL *gFSgl; /* line 24 */
Then again you haven't shown us enough code so that we'd be able to
compile it anyway.
--
Keith Thompson (The_Other_Keith) (e-mail address removed)  <http://www.ghoti.net/~kst>
Nokia
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"

Thanks guys.

I figured out the reason why I made such kind of mistake. Basically it
is a bad practice of writing code.

Usually, I put the type definitions in header files, and then if some
other files want to use these type definitions, I just use the
#include. In this way, the files using these type definition may be
included before the real type definition. So it will give you some
weird error msgs...

A good way (at least I think) to debug this error is to use "gcc -E
*.c", then you can check the preprocessing file very easily:)

For instance,
----A.h-----
#ifndef A_H_
#define A_H_

#include "C.h"

typedef struct{
    int x;
    int y;

}NODE;

void bar();
#endif

----A.c----
#include "A.h"

void bar(){
    foo();

}

----C.h------
#ifndef C_H_
#define C_H_

#include "A.h"

Node foo(); /* need to use type NODE defined in A.h */

#endif

----C.c----
#include "C.h"

Node foo(){}

----main.c----
#include "A.h"
int main(){
    bar();
    return 1;

}

if you try to compile this code, you will get error msgs like:
-----------------------------------
gcc -O2 -g -Wall -fmessage-length=0   -c -o main.o main.c
In file included from A.h:6,
                 from main.c:3:
C.h:6: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before
‘foo’
make: *** [main.o] Error 1


One more Makefile

--------------------- Makefile -------------------
CC = gcc
CFLAGS = -O2 -g -Wall -fmessage-length=0
LIBS = -lm
TARGET = main
OBJECTS = main.o \
C.o \
A.o

$(TARGET): $(OBJECTS)
$(CC) -g -o $(TARGET) $(OBJECTS) $(LIBS)

all: $(TARGET)

clean:
rm -f $(TARGET) $(OBJECTS)
---------------------------------------------------
 
N

Nate Eldredge

Andy said:
I figured out the reason why I made such kind of mistake. Basically it
is a bad practice of writing code.

Usually, I put the type definitions in header files, and then if some
other files want to use these type definitions, I just use the
#include. In this way, the files using these type definition may be
included before the real type definition. So it will give you some
weird error msgs...

A good way (at least I think) to debug this error is to use "gcc -E
*.c", then you can check the preprocessing file very easily:)

For instance,
----A.h-----
#ifndef A_H_
#define A_H_

#include "C.h"

typedef struct{
int x;
int y;
}NODE;

void bar();
#endif

----A.c----
#include "A.h"

void bar(){
foo();
}

----C.h------
#ifndef C_H_
#define C_H_

#include "A.h"

Node foo(); /* need to use type NODE defined in A.h */

#endif

----C.c----
#include "C.h"

Node foo(){}


----main.c----
#include "A.h"
int main(){
bar();
return 1;
}


if you try to compile this code, you will get error msgs like:
-----------------------------------
gcc -O2 -g -Wall -fmessage-length=0 -c -o main.o main.c
In file included from A.h:6,
from main.c:3:
C.h:6: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before
‘foo’
make: *** [main.o] Error 1
-----------------------------------


Is there some good way to avoid this bad practice? Currently, I just
put these definitions into type.h, which is shared as common header.

Fundamentally, the problem is that A.h and C.h both include each other.
Having a loop like this is never going to work, it's just that your
include guards make it fail in a slightly more mysterious way.

In this case, there is no need for A.h to include C.h, so you could just
that #include and everything would be fine (also correct the spelling of
Node/NODE to be consistent). If A.h really does need some things that
are in C.h, they should be broken out into a third header file which can
be included by both A.h and C.h. If the dependencies are more
complicated, more files might be needed, but there should always be a
way to resolve it without loops.
 
A

Andy

Andy said:
I figured out the reason why I made such kind of mistake. Basically it
is a bad practice of writing code.
Usually, I put the type definitions in header files, and then if some
other files want to use these type definitions, I just use the
#include. In this way, the files using these type definition may be
included before the real type definition. So it will give you some
weird error msgs...
A good way (at least I think) to debug this error is to use "gcc -E
*.c", then you can check the preprocessing file very easily:)
For instance,
----A.h-----
#ifndef A_H_
#define A_H_
#include "C.h"
typedef struct{
    int x;
    int y;
}NODE;
void bar();
#endif
----A.c----
#include "A.h"
void bar(){
    foo();
}
----C.h------
#ifndef C_H_
#define C_H_
#include "A.h"
Node foo(); /* need to use type NODE defined in A.h */

----C.c----
#include "C.h"
Node foo(){}
----main.c----
#include "A.h"
int main(){
    bar();
    return 1;
}
if you try to compile this code, you will get error msgs like:
-----------------------------------
gcc -O2 -g -Wall -fmessage-length=0   -c -o main.o main.c
In file included from A.h:6,
                 from main.c:3:
C.h:6: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before
‘foo’
make: *** [main.o] Error 1
-----------------------------------
Is there some good way to avoid this bad practice? Currently, I just
put these definitions into type.h, which is shared as common header.

Fundamentally, the problem is that A.h and C.h both include each other.
Having a loop like this is never going to work, it's just that your
include guards make it fail in a slightly more mysterious way.

In this case, there is no need for A.h to include C.h, so you could just
that #include and everything would be fine (also correct the spelling of
Node/NODE to be consistent).  If A.h really does need some things that
are in C.h, they should be broken out into a third header file which can
be included by both A.h and C.h.  If the dependencies are more
complicated, more files might be needed, but there should always be a
way to resolve it without loops.

I C. I think I learned somewhere saying "loop #include does not matter
as long as you guard it using #ifndef".
Obviously, it is not a good practice here.. It complicated the
problem... As you said, split them out...

However, I think self-looping of the #include is fine, in this way, we
do not need to care the order of the functions when defining them. Am
I right? or there is better way to handle it? Thanks!

A.W.
 
L

luserXtrog

Andy said:
I figured out the reason why I made such kind of mistake. Basically it
is a bad practice of writing code.
Usually, I put the type definitions in header files, and then if some
other files want to use these type definitions, I just use the
#include. In this way, the files using these type definition may be
included before the real type definition. So it will give you some
weird error msgs...
A good way (at least I think) to debug this error is to use "gcc -E
*.c", then you can check the preprocessing file very easily:)
For instance,
----A.h-----
#ifndef A_H_
#define A_H_
#include "C.h"
typedef struct{
    int x;
    int y;
}NODE;
void bar();
#endif
----A.c----
#include "A.h"
void bar(){
    foo();
}
----C.h------
#ifndef C_H_
#define C_H_
#include "A.h"
Node foo(); /* need to use type NODE defined in A.h */
#endif
----C.c----
#include "C.h"
Node foo(){}
----main.c----
#include "A.h"
int main(){
    bar();
    return 1;
}
if you try to compile this code, you will get error msgs like:
-----------------------------------
gcc -O2 -g -Wall -fmessage-length=0   -c -o main.o main.c
In file included from A.h:6,
                 from main.c:3:
C.h:6: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before
‘foo’
make: *** [main.o] Error 1
Fundamentally, the problem is that A.h and C.h both include each other.
Having a loop like this is never going to work, it's just that your
include guards make it fail in a slightly more mysterious way.
In this case, there is no need for A.h to include C.h, so you could just
that #include and everything would be fine (also correct the spelling of
Node/NODE to be consistent).  If A.h really does need some things that
are in C.h, they should be broken out into a third header file which can
be included by both A.h and C.h.  If the dependencies are more
complicated, more files might be needed, but there should always be a
way to resolve it without loops.

I C. I think I learned somewhere saying "loop #include does not matter
as long as you guard it using #ifndef".
Obviously, it is not a good practice here.. It complicated the
problem... As you said, split them out...

However, I think self-looping of the #include is fine, in this way, we
do not need to care the order of the functions when defining them. Am
I right? or there is better way to handle it? Thanks!

A.W.

I'd recommend keeping the guards, but removing all #includes from
all .h files. If a header file requires definitions from another
header, it can have a brief comment to that effect. This forces
all the inclusions to take place in the .c file where they exist
on the same level and can be easily rearranged to follow the
dependencies. The circularity is relieved by the linear nature of
the text file: one of 'em's got to be first.
 
K

Keith Thompson

luserXtrog said:
I'd recommend keeping the guards, but removing all #includes from
all .h files. If a header file requires definitions from another
header, it can have a brief comment to that effect. This forces
all the inclusions to take place in the .c file where they exist
on the same level and can be easily rearranged to follow the
dependencies. The circularity is relieved by the linear nature of
the text file: one of 'em's got to be first.

I disagree. There's nothing wrong with having #includes in header
files. If I need the functionality defined in foo.h, and foo.h needs
the functionality defined in btfsplk.h, it's foo.h's job to #include
"btfsplk.h" for itself. If a later version of foo.h also needs
functionality defined in rxuqnxbh.h, I shouldn't have to change my
code.

For example, stdio.h on my system has the following #include
directives:

#include <libio.h>
#include <bits/stdio_lim.h>
#include <bits/sys_errlist.h>

Should my "Hello, world" program include all four headers itself?
 
L

luserXtrog

[...]
I'd recommend keeping the guards, but removing all #includes from
all .h files. If a header file requires definitions from another
header, it can have a brief comment to that effect. This forces
all the inclusions to take place in the .c file where they exist
on the same level and can be easily rearranged to follow the
dependencies. The circularity is relieved by the linear nature of
the text file: one of 'em's got to be first.

I disagree.  There's nothing wrong with having #includes in header
files.  If I need the functionality defined in foo.h, and foo.h needs
the functionality defined in btfsplk.h, it's foo.h's job to #include
"btfsplk.h" for itself.  If a later version of foo.h also needs
functionality defined in rxuqnxbh.h, I shouldn't have to change my
code.

There is at least one thing wrong with it. The very issue of this
thread.
For example, stdio.h on my system has the following #include
directives:

#include <libio.h>
#include <bits/stdio_lim.h>
#include <bits/sys_errlist.h>

Should my "Hello, world" program include all four headers itself?

So library headers are considered a good model for writing new code?
Isn't one of the commandments about this?
 
J

jameskuyper

luserXtrog wrote:
....
I'd recommend keeping the guards, but removing all #includes from
all .h files. If a header file requires definitions from another
header, it can have a brief comment to that effect. This forces
all the inclusions to take place in the .c file where they exist
on the same level and can be easily rearranged to follow the
dependencies. The circularity is relieved by the linear nature of
the text file: one of 'em's got to be first.

I disagree most strenuously. Every header file should #include
everything it needs to be a complete (though empty) translation unit
on it's own - anything less than that just produces maintenance
nightmares in the long run.

In my own group, I insist that every header file must pass the
following test: create a source code file that does nothing but
#include the header file twice, and define a global int variable whose
name doesn't conflict with anything in the header file (to shut off
warnings about an empty file). That source code file should compile
without any important warnings or error messages, when the compiler is
set to it's pickiest settings. This isn't the only requirement I
insist on for header files, it's just one of the simplest to verify.
 
A

Andy

I'd recommend keeping the guards, but removing all #includes from
all .h files. If a header file requires definitions from another
header, it can have a brief comment to that effect. This forces
all the inclusions to take place in the .c file where they exist
on the same level and can be easily rearranged to follow the
dependencies. The circularity is relieved by the linear nature of
the text file: one of 'em's got to be first.
I disagree.  There's nothing wrong with having #includes in header
files.  If I need the functionality defined in foo.h, and foo.h needs
the functionality defined in btfsplk.h, it's foo.h's job to #include
"btfsplk.h" for itself.  If a later version of foo.h also needs
functionality defined in rxuqnxbh.h, I shouldn't have to change my
code.

There is at least one thing wrong with it. The very issue of this
thread.
For example, stdio.h on my system has the following #include
directives:
#include <libio.h>
#include <bits/stdio_lim.h>
#include <bits/sys_errlist.h>
Should my "Hello, world" program include all four headers itself?

So library headers are considered a good model for writing new code?
Isn't one of the commandments about this?

I think both of your guys argument are right. It depends on which kind
of .h you are including.

What I am thinking is: we could classify three levels of .h.
--------------------------------------------------------------------
libio.h, bits/stdio_lim.h, bits/sys_errlist.h...................,
etc. 0 level
--------------------------------------------------------------------
^ ^
| |
--------------------------------------------------------------------
stdio.h, stdlib.h, string.h....................................,
etc. 1 level
--------------------------------------------------------------------
^ ^
| |
--------------------------------------------------------------------
foo.h, bar.h, hhhhh.h..........................................,
etc. 2 level
--------------------------------------------------------------------

If the upper level of .h is wanted, we can safely include them
into .h. However, including the same level .h in the .h will be a bad
practice (I guess so). In this way, no looping #include could ever
happen.

A.W.
 
J

jameskuyper

luserXtrog said:
[...]
I'd recommend keeping the guards, but removing all #includes from
all .h files. If a header file requires definitions from another
header, it can have a brief comment to that effect. This forces
all the inclusions to take place in the .c file where they exist
on the same level and can be easily rearranged to follow the
dependencies. The circularity is relieved by the linear nature of
the text file: one of 'em's got to be first.

I disagree. There's nothing wrong with having #includes in header
files. If I need the functionality defined in foo.h, and foo.h needs
the functionality defined in btfsplk.h, it's foo.h's job to #include
"btfsplk.h" for itself. If a later version of foo.h also needs
functionality defined in rxuqnxbh.h, I shouldn't have to change my
code.

There is at least one thing wrong with it. The very issue of this
thread.

That's because the #includes are being used incorrectly; the right
solution is to use them correctly, not to avoid using them altogether.
A.h had no reason for #including C.h. In general, you can solve any
such problem by
 
J

jameskuyper

luserXtrog said:
[...]
I'd recommend keeping the guards, but removing all #includes from
all .h files. If a header file requires definitions from another
header, it can have a brief comment to that effect. This forces
all the inclusions to take place in the .c file where they exist
on the same level and can be easily rearranged to follow the
dependencies. The circularity is relieved by the linear nature of
the text file: one of 'em's got to be first.

I disagree. There's nothing wrong with having #includes in header
files. If I need the functionality defined in foo.h, and foo.h needs
the functionality defined in btfsplk.h, it's foo.h's job to #include
"btfsplk.h" for itself. If a later version of foo.h also needs
functionality defined in rxuqnxbh.h, I shouldn't have to change my
code.

There is at least one thing wrong with it. The very issue of this
thread.

That's because the #includes are being used incorrectly; the right
solution is to use them correctly, not to avoid using them altogether.
A.h had no reason for #including C.h. You could have defined things in
such a way that A.h and C.h each defined something needed in the other
file. However, in general, you can solve any such problem by
rearranging which things are defined in which header file. In the
extreme case, if you can't solve the problem by putting everything
together in a single header file, then it's a problem with the C
language, not a problem with the #includes. Example: mutually
recursive struct types.
 
N

Nate Eldredge

Keith Thompson said:
Each header should, ideally at least, define a coherent interface to
be used by client code. The header should, IMNSHO, do whatever it
needs to do to provide that interface in a usable form. If I need to
use an interface defined by "foo.h", providing
#include "foo.h"
should be sufficient (along with whatever linker option I need to load
the corresponding library). As I said, if foo.h depends on btfsplk.h,
it's not the client's responsibility to write
#include "btfsplk.h"
any more than it's the client's responsibility to write
typedef struct foo { /* ... */ };

That's a good rule. A header should certainly be responsible for
including the things it needs in order to compile.

At a higher level, for an "interface" consisting of several functions,
objects, etc, it's nice when there's a single header that declares all
of them. I'm frequently annoyed by POSIX's specification that the
`open' function (with associated macros) is declared in <fcntl.h>, but
`close' is in <unistd.h>, despite the fact that one rarely wants one
without the other.
 
A

Andy

That's a good rule.  A header should certainly be responsible for
including the things it needs in order to compile.

At a higher level, for an "interface" consisting of several functions,
objects, etc, it's nice when there's a single header that declares all
of them.  I'm frequently annoyed by POSIX's specification that the
`open' function (with associated macros) is declared in <fcntl.h>, but
`close' is in <unistd.h>, despite the fact that one rarely wants one
without the other.

I am a little confused...

For instance:
---- type.h ----

typedef struct node{
int x;

}

---- head.h ----
 
A

Andy

That's a good rule.  A header should certainly be responsible for
including the things it needs in order to compile.

At a higher level, for an "interface" consisting of several functions,
objects, etc, it's nice when there's a single header that declares all
of them.  I'm frequently annoyed by POSIX's specification that the
`open' function (with associated macros) is declared in <fcntl.h>, but
`close' is in <unistd.h>, despite the fact that one rarely wants one
without the other.

I am a little confused...

For instance:

------------
* option 1 *
------------

---- type.h ----
typedef struct node{
int x;
int y;
}NODE;


---- foo.h ----
#include "type.h"

NODE foo(); /* need to see the definition of NODE here */


---- foo.c ----
#include "foo.h"

NODE foo(){}; /* it is included in foo.h already */

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

------------
* option 2 *
------------

---- type.h ----
typedef struct node{
int x;
int y;
}NODE;


---- foo.h ----

NODE foo(); /* need to see NODE definition, but NOT included */


---- foo.c ----
#include "type.h" /* has to #include before foo.h, o/w foo.h cannot
see NODE definition */
#include "foo.h"

NODE foo(){};


Personally, I prefer "option 1", then I do not need to worry about the
order of the #includes. However, "option 1" could lead to the problem
I had before. Probably I should avoid using looping #includes...

A.W.
 
J

jameskuyper

Andy wrote:
....
I am a little confused...

For instance:

------------
* option 1 *
------------

---- type.h ----
typedef struct node{
int x;
int y;
}NODE;


---- foo.h ----
#include "type.h"

NODE foo(); /* need to see the definition of NODE here */


---- foo.c ----
#include "foo.h"

NODE foo(){}; /* it is included in foo.h already */

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

------------
* option 2 *
------------

---- type.h ----
typedef struct node{
int x;
int y;
}NODE;


---- foo.h ----

NODE foo(); /* need to see NODE definition, but NOT included */


---- foo.c ----
#include "type.h" /* has to #include before foo.h, o/w foo.h cannot
see NODE definition */
#include "foo.h"

NODE foo(){};


Personally, I prefer "option 1", then I do not need to worry about the
order of the #includes. However, "option 1" could lead to the problem
I had before.

Not if you avoid #including files that don't need to be #included.
 

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,994
Messages
2,570,223
Members
46,812
Latest member
GracielaWa

Latest Threads

Top