Declaring an external variable as a struct

M

Mark Hobley

I have created header file buffers.h as follows:

struct buffertablestru {
char *addr;
int numbuffers;
};

extern buffertablestru buffertable;

When included in a file, this is supposed to tell programs that there is an
external variable buffertable with a structure of buffertablestru.

The program buffers.c is provides the variable buffertable, which can then
be accessed by other modules:

#include "buffers.h"

buffertablestru buffertable; /* Define the variable buffertable */

int main() {

/* blah blah blah */
}

For some reason I am getting a compiler error, when I attempt to compile
buffers.c:

In file included from buffers.c:1:
buffers.h:7: error: expected '=', ',', ';', 'asm' or '__attribute__' before
'buffertable'
buffers.c:3: error: expected '=', ',', ';', 'asm' or '__attribute__' before
'buffertable'

What is wrong here?

Mark.
 
I

Ian Collins

I have created header file buffers.h as follows:

struct buffertablestru {
char *addr;
int numbuffers;
};

extern buffertablestru buffertable;

A better form of naming will go a long way to making your code more
readable!

Either buffer_table_stru or bufferTableStru are common styles. What's a
"stru"?
When included in a file, this is supposed to tell programs that there is an
external variable buffertable with a structure of buffertablestru.

The program buffers.c is provides the variable buffertable, which can then
be accessed by other modules:

#include "buffers.h"

buffertablestru buffertable; /* Define the variable buffertable */
Both hare and the declaration above are missing the "struct" keyword.

struct buffertablestru buffertable;

Or you could precede the struct declaration with

typedef struct buffertablestru buffertablestru;
 
K

Keith Thompson

I have created header file buffers.h as follows:

struct buffertablestru {
char *addr;
int numbuffers;
};

This declared a type named "struct buffertablestru".
extern buffertablestru buffertable;

This attempts to declare an object of type "buffertablestru". You
haven't declared a type by that name.

You can either refer to the type by its correct name (this would be my
preference):

extern struct buffertablestru buffertable;

or you can create a typedef:

typedef struct buffertablestru {
char *addr;
int numbuffers;
} buffertablestru;

extern buffertablestru buffertable;

<OT>In C++, declaring a type as "struct foo" allows you to refer to it
either as "struct foo" or as "foo". C doesn't do that.</OT>
 
M

Mark Hobley

Ian Collins said:
Either buffer_table_stru or bufferTableStru are common styles. What's a
"stru"?

I prefer identifiers to be lowercase and without underscores and capitals. I
tend to use lowercase names and just use a suffix of "stru" to highlight this
as being a structure name rather than a variable.
Both hare and the declaration above are missing the "struct" keyword.

Right I fixed that:

buffers.h:

extern struct buffertablestru buffertable;

buffers.c:

#include "buffers.h"
struct buffertablestru buffertable;

I have another little problem now though:

buffers.h also defines another structure:

struct bufstru {
char *addr;
int sz;
int ptr;
int tail;
};

In buffer.c, I have a function dynalloc as follows:

int dynalloc(struct bufstru *buffer) {
flag err = FALSE;
if (buffer.addr == NULL) { <--- This line gives an error
/* allocate the buffer */
/* configure the head and tail */
} else {
/* buffer is already allocated */
}
}

I am getting a compilation error as follows:

buffers.c:56: error: request for member 'addr' in something not a structure
or union

What I am trying to do here is to determine if the element buffer.addr
already contains a valid address.

Mark.
 
B

Ben Pfaff

I prefer identifiers to be lowercase and without underscores and capitals. I
tend to use lowercase names and just use a suffix of "stru" to highlight this
as being a structure name rather than a variable.


Right I fixed that:

buffers.h:

extern struct buffertablestru buffertable;

I'm surprised that the "struct " prefix isn't enough to highlight
that the identifier is a structure name, so that you need a
"stru" suffix also.
 
I

Ian Collins

I prefer identifiers to be lowercase and without underscores and capitals. I
tend to use lowercase names and just use a suffix of "stru" to highlight this
as being a structure name rather than a variable.

That (in the eyes of most readers) will make your code hard to read and
maintain.
I have another little problem now though:

buffers.h also defines another structure:

struct bufstru {
char *addr;
int sz;
int ptr;
int tail;
};

In buffer.c, I have a function dynalloc as follows:

int dynalloc(struct bufstru *buffer) {
flag err = FALSE;
if (buffer.addr == NULL) {<--- This line gives an error

As it should, butter is a pointer to a bufstru, no a bufstru. Use

buffer->addr == NULL

You should probably check to make sure buffer isn't NULL before you
proceed to dereference it.
 
M

Mark Hobley

Ian Collins said:
As it should, butter is a pointer to a bufstru, no a bufstru. Use

buffer->addr == NULL

Sorry Ian. My bad C is misleading you. That is not my intention.

struct bufstru {
char *addr;
int sz;
int ptr;
int tail;
};

int dynalloc(struct bufstru *buffer);

buffer is a structure of type bufstru whose address is passed as a parameter
to dynalloc. (I am also guessing here that the structure would be passed by
reference, rather than via the stack, making the function dynalloc capable of
changing the values in the pointed at structure, rather than in the stack
variable, so that the values are not lost when the function returns. At least,
that is my intention.)

The element buffer.addr of the pointed at structure will point to a newly
allocated dynamic buffer which will subsequently be used by various string
manipulation processes.

The check that addr is null pointer is a safety check to ensure that the
buffer is not allocated.

I planned to use the following convention:

If the buffer has not been allocated, its address will be NULL (as in a
null pointer), otherwise, its address will be a valid address.

Next, I will calloc to allocate the buffer.

FWIW:

buffer.sz will be the total number of bytes that the buffer can contain.
buffer.ptr, will be the write position head. (The next character to bewritten
will be placed at the address equal to buffer.addr+buffer.ptr).

The tail is a supplementary variable that is only used within circular buffer
applications.

There can be more than one buffer used from within a program, which is why
I am trying to pass the address of the variable holding the buffer information,
rather than having a single variable named buffer.

The information about all of the buffers in use on the system will be held in
a buffertable, (of type buffertablestru, which is the structure and variable,
that I used earlier). There is only one buffertable in the program, and this
will be globally available.

Maybe I got the prototype wrong.

int dynalloc(struct bufstru *buffer);

Do I pass the structure type in a prototype?

or should this be just as below?

int dynalloc(*buffer);

(If I do not pass the prototype, how would the function know that the
address given is a pointer to a bufstru structure?, and how would I
reference the elements of the structure?)

Mark.
 
I

Ian Collins

Sorry Ian. My bad C is misleading you. That is not my intention.

struct bufstru {
char *addr;
int sz;
int ptr;
int tail;
};

int dynalloc(struct bufstru *buffer);

buffer is a structure of type bufstru whose address is passed as a parameter
to dynalloc. (I am also guessing here that the structure would be passed by
reference, rather than via the stack, making the function dynalloc capable of
changing the values in the pointed at structure, rather than in the stack
variable, so that the values are not lost when the function returns. At least,
that is my intention.)

C doesn't have pass by reference. Passing a pointer is as close as you
can get.
The element buffer.addr of the pointed at structure will point to a newly
allocated dynamic buffer which will subsequently be used by various string
manipulation processes.

But as I said, butter is a pointer to a bufstru, no a bufstru.

Maybe I got the prototype wrong.

int dynalloc(struct bufstru *buffer);

Do I pass the structure type in a prototype?

You pass a pointer to the structure.
 
M

Mark Hobley

Ian Collins said:
You pass a pointer to the structure.

This is what I am trying to do. I do not understand why struct bufstru *
is not a pointer to a bufstru structure in the context of the prototype.

int dynalloc(struct bufstru *buffer);

Doesn't the star mean that this a pointer?

Mark.
 
N

Nick Keighley

This is what I am trying to do. I do not understand why struct bufstru *
is not a pointer to a bufstru structure in the context of the prototype.

int dynalloc(struct bufstru *buffer);

Doesn't the star mean that this a pointer?

yes. But you aren't /using/ it as pointer. This would be easier if you
left more context in your posts.

Get a good tutorial such as K&R
 
M

Mark Hobley

Nick Keighley said:
yes. But you aren't /using/ it as pointer. This would be easier if you
left more context in your posts.

Ok. I don't understand. What context am I missing? I have a function, and I
will pass to it the address of a structure. I will be referencing elements of
the structure from within the function.
Get a good tutorial such as K&R

Actually, I do have a copy of this somewhere, but I have somehow mislaid it
at this time. (I carry it round with me).

Mark.
 
I

Ian Collins

Ok. I don't understand. What context am I missing? I have a function, and I
will pass to it the address of a structure. I will be referencing elements of
the structure from within the function.

Yes, we know. But you are not doing so via an instance of the
structure, but via a pointer to an instance. The distinction is very
important and a fundamental part of understanding C.
 
J

James Lothian

Mark said:
I prefer identifiers to be lowercase and without underscores and capitals. I
tend to use lowercase names and just use a suffix of "stru" to highlight this
as being a structure name rather than a variable.


Right I fixed that:

buffers.h:

extern struct buffertablestru buffertable;

buffers.c:

#include "buffers.h"
struct buffertablestru buffertable;

I have another little problem now though:

buffers.h also defines another structure:

struct bufstru {
char *addr;
int sz;
int ptr;
int tail;
};

In buffer.c, I have a function dynalloc as follows:

int dynalloc(struct bufstru *buffer) {
flag err = FALSE;
if (buffer.addr == NULL) {<--- This line gives an error

buffer is a pointer, not an object. You need to dereference the pointer:
if( (*buffer).addr == NULL )
or equivalently and more idiomatically:
if(buffer -> addr == NULL)
You also need to get yourself a good C book and actually read it.

James
 
M

Mark Hobley

Ian Collins said:
Yes, we know. But you are not doing so via an instance of the
structure, but via a pointer to an instance. The distinction is very
important and a fundamental part of understanding C.

Ok. I don't understand. Could anyone provide a small example to illustrate this
point, (ie the difference between an instance of a structure and a pointer to
an instance).

I think you might be saying that I am expecting the address of a pointer to a
structure, rather than the address of a structure. Is that right?

Should I be using an address operator in the prototype here?

eg:

int dynalloc(struct bufstru &buffer)

or

int dynalloc(&struct bufstru buffer)

Are address operators used in prototypes in this manner?

Mark.
 
N

Nick

Ok. I don't understand. Could anyone provide a small example to illustrate this
point, (ie the difference between an instance of a structure and a pointer to
an instance).

I think you might be saying that I am expecting the address of a pointer to a
structure, rather than the address of a structure. Is that right?

No, you're expecting a pointer to a structure, not a structure. You
can't access a member of a pointer, so you need to either turn the
pointer into a structure before accessing a member of it (messy) or use
the special syntax for accessing a member of a structure that is pointed
to by a pointer you have.
Should I be using an address operator in the prototype here?

No! The prototype is fine, it's what you're doing with the local
variable that's wrong.

You really /do/ need to read a bit more, and then come back - this isn't
the best way to learn a language!
 
B

Ben Bacarisse

Ok. I don't understand. Could anyone provide a small example to
illustrate this point, (ie the difference between an instance of a
structure and a pointer to an instance).

Does this help:

#include <stdio.h>

struct example {
int i;
};

void print_and_change_from_struct(struct example e)
{
e.i = 0;
printf("e.i now %d\n", e.i);
}

void print_and_change_from_pointer(struct example *ep)
{
ep->i = 0;
printf("ep->i now %d\n", ep->i);
}

int main(void)
{
struct example eg = {42};
print_and_change_from_struct(eg);
printf("eg.i = %d\n", eg.i);
print_and_change_from_pointer(&eg);
printf("eg.i = %d\n", eg.i);
return 0;
}

<snip>
 
M

Mark Hobley

Mark Hobley said:
I have created header file buffers.h as follows:

struct buffertablestru {
char *addr;
int numbuffers;
};

extern struct buffertablestru buffertable;

I now define an external variable buffertable with a structure of
buffertablestru in buffers.c as follows:

# include "buffers.h"

struct buffertablestru buffertable = {
NULL,
0
};

This seems to be working ok now. Thanks to everyone who helped me here.
I have another query now though.

Suppose that in future, I decided to add an element to buffertablestru in
buffers.h as follows:

struct buffertablestru {
char *addr;
int futurethingy; /* <---- I have added an element */
int numbuffers;
}

The above modification would break buffers.c because I would now need to
update the definition of buffertable, because the elements are now misaligned
to the declaration.

It would be better, if I could somehow use the element names in the definition
to prevent a misalignment:

struct buffertablestru buffertable = {
addr == NULL,
numbuffers == 0
};

Does C support anything like this, maybe by providing initial values in the
header against the elements (as part of the declaration), or what is
recommended practice here, in terms of keeping declarations in a header file
in sync with the definition in the program file?

(I am using C89 if that matters.)

Mark.
 
M

Morris Keesan

I now define an external variable buffertable with a structure of
buffertablestru in buffers.c as follows:

# include "buffers.h"

struct buffertablestru buffertable = {
NULL,
0
};

This seems to be working ok now. Thanks to everyone who helped me here.
I have another query now though.

Suppose that in future, I decided to add an element to buffertablestru in
buffers.h as follows:

struct buffertablestru {
char *addr;
int futurethingy; /* <---- I have added an element */
int numbuffers;
}

The above modification would break buffers.c because I would now need to
update the definition of buffertable, because the elements are now
misaligned
to the declaration.

It would be better, if I could somehow use the element names in the
definition
to prevent a misalignment:

struct buffertablestru buffertable = {
addr == NULL,
numbuffers == 0
};

Does C support anything like this, maybe by providing initial values in
the
header against the elements (as part of the declaration), or what is
recommended practice here, in terms of keeping declarations in a header
file
in sync with the definition in the program file?

(I am using C89 if that matters.)

I C89, you can't declare arbitrary initial values for structure members
while keeping the initialization safe from structure modifications.
In C99, or with a compiler which supports this feature of C99, you can
give the names of the structure members being initialized, viz:

struct buffertablestru buffertable = {
.addr = NULL;
.numbuffers = 0;
}

(see 6.7.8 of ISO/IEC 9899:1999).

The good news is that, if you don't want arbitrary initial values, but
are really going to continue initializing these values to NULL and 0, then
you don't even need to explicitly initialize this particular object,
because
objects with external storage class get initialized to the appropriate
kinds
of zero (0, NULL, 0.0, etc.) by default.

In any case, good practice would be to add new structure members only at
end of the structure, rather than in the middle, in order to avoid just the
kind of problem you're anticipating. You could even add a comment to the
structure declaration warning of problems if members are inserted other
than at the end.
 
B

Ben Bacarisse

I now define an external variable buffertable with a structure of
buffertablestru in buffers.c as follows:

# include "buffers.h"

struct buffertablestru buffertable = {
NULL,
0
};

This seems to be working ok now. Thanks to everyone who helped me here.
I have another query now though.

Suppose that in future, I decided to add an element to buffertablestru in
buffers.h as follows:

struct buffertablestru {
char *addr;
int futurethingy; /* <---- I have added an element */

BTW, it's called a member not an element, though it is an element in
the normal English sense of the word.
int numbuffers;
}

The above modification would break buffers.c because I would now need to
update the definition of buffertable, because the elements are now misaligned
to the declaration.

I see what you mean but that is not how C uses the term "aligned".
When you change x.h all source files that #include "x.h" should be
re-compiled.
It would be better, if I could somehow use the element names in the definition
to prevent a misalignment:

struct buffertablestru buffertable = {
addr == NULL,
numbuffers == 0
};

Yes it does. C99 has "designated initialisers", but they don't solve
the problem. However you write the initialisation, the code is wrong
if two parts of it were compiled with different ideas about what a
'struct buffertablestru' is.

If you add members only at the end, you will probably get away with it
but the program is still "wrong" and the parts the depend on the
structure still need to be re-compiled.
Does C support anything like this, maybe by providing initial values in the
header against the elements (as part of the declaration), or what is
recommended practice here, in terms of keeping declarations in a header file
in sync with the definition in the program file?

Most systems have some way to build a program that re-compiles the
right bits depending on which bits have changed.
 
K

Keith Thompson

Morris Keesan said:
The good news is that, if you don't want arbitrary initial values, but
are really going to continue initializing these values to NULL and 0, then
you don't even need to explicitly initialize this particular object,
because
objects with external storage class get initialized to the appropriate
kinds
of zero (0, NULL, 0.0, etc.) by default.
[...]

You mean static storage class, not external storage class ("external"
is a linkage).

Even for objects with automatic storage class, if there's an
initializer at all then any elements not specified by the initializer
are set to the appropriate kind of zero. This:

struct my_struct obj = { 0 };

is valid for any struct type -- in fact, it's valid for any object
type. (Some compilers, particularly gcc, tend to warn about this
idiom, since some but not all members are explicitly initialized.)
 

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,768
Messages
2,569,574
Members
45,049
Latest member
Allen00Reed

Latest Threads

Top