Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Declaring an external variable as a struct

0 views
Skip to first unread message

Mark Hobley

unread,
Mar 25, 2010, 2:42:10 AM3/25/10
to
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.

--
Mark Hobley
Linux User: #370818 http://markhobley.yi.org/

Ian Collins

unread,
Mar 25, 2010, 3:16:28 AM3/25/10
to
On 03/25/10 07:42 PM, Mark Hobley wrote:
> 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;

--
Ian Collins

Keith Thompson

unread,
Mar 25, 2010, 3:48:56 AM3/25/10
to
markh...@hotpop.donottypethisbit.com (Mark Hobley) writes:
> 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>

--
Keith Thompson (The_Other_Keith) ks...@mib.org <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"

Mark Hobley

unread,
Mar 25, 2010, 4:25:01 PM3/25/10
to
Ian Collins <ian-...@hotmail.com> wrote:
> 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.

Ben Pfaff

unread,
Mar 25, 2010, 5:23:22 PM3/25/10
to
markh...@hotpop.donottypethisbit.com (Mark Hobley) writes:

> Ian Collins <ian-...@hotmail.com> wrote:
> 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;

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.
--
Ben Pfaff
http://benpfaff.org

Ian Collins

unread,
Mar 25, 2010, 6:14:17 PM3/25/10
to
On 03/26/10 09:25 AM, Mark Hobley wrote:
> Ian Collins<ian-...@hotmail.com> wrote:
>> 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.

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.

--
Ian Collins

Mark Hobley

unread,
Mar 26, 2010, 1:01:23 AM3/26/10
to
Ian Collins <ian-...@hotmail.com> wrote:
>> 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

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?)

Ian Collins

unread,
Mar 26, 2010, 2:51:23 AM3/26/10
to

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.

<snip>

> 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.

--
Ian Collins

Mark Hobley

unread,
Mar 26, 2010, 3:40:30 AM3/26/10
to
Ian Collins <ian-...@hotmail.com> wrote:

> 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?

Nick Keighley

unread,
Mar 26, 2010, 4:26:38 AM3/26/10
to
On 26 Mar, 07:40, markhob...@hotpop.donottypethisbit.com (Mark Hobley)
wrote:

> Ian Collins <ian-n...@hotmail.com> wrote:
> > 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?

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

Mark Hobley

unread,
Mar 26, 2010, 7:59:53 PM3/26/10
to
Nick Keighley <nick_keigh...@hotmail.com> wrote:
> 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).

Ian Collins

unread,
Mar 26, 2010, 8:44:11 PM3/26/10
to
On 03/27/10 12:59 PM, Mark Hobley wrote:
> Nick Keighley<nick_keigh...@hotmail.com> wrote:
>> 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.

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.

--
Ian Collins

James Lothian

unread,
Mar 26, 2010, 9:47:20 PM3/26/10
to

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


Mark Hobley

unread,
Mar 27, 2010, 5:17:41 AM3/27/10
to
Ian Collins <ian-...@hotmail.com> wrote:
> 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?

Nick

unread,
Mar 27, 2010, 6:16:42 AM3/27/10
to
markh...@hotpop.donottypethisbit.com (Mark Hobley) writes:

> Ian Collins <ian-...@hotmail.com> wrote:
>> 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?

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!
--
Online waterways route planner | http://canalplan.eu
Plan trips, see photos, check facilities | http://canalplan.org.uk

Bill Waddington

unread,
Mar 27, 2010, 10:05:19 AM3/27/10
to
On Sat, 27 Mar 2010 09:17:41 +0000,
markh...@hotpop.donottypethisbit.com (Mark Hobley) wrote:

>Ian Collins <ian-...@hotmail.com> wrote:
>> 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).

Mark,

You are chasing your tail on this one.

Ian answered this in his 2nd reply. Let me (the world's crappiest C
coder) repeat it:

>> 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

That's how you access an element of a structure pointed to by
"buffer". Your buffer.add is how you access an element of a
structure directly.

The "->" idiom means (in TWCCC's terms) get me the element named
on the right of the -> from the structure _pointed to_ by the thing
on the left of the ->.

Since you like tacking "stru" on the end of struct names, you might
consider adding "p" or "poi" :) to the end of your pointers.

Apologies to the regulars for sticking my beak in. Couldn't stand
to watch the train wreck :)

Later,
Bill (TWCCC)

--
William D Waddington
william.w...@beezmo.com
"Even bugs...are unexpected signposts on
the long road of creativity..." - Ken Burtch

Ben Bacarisse

unread,
Mar 27, 2010, 11:11:11 AM3/27/10
to
markh...@hotpop.donottypethisbit.com (Mark Hobley) writes:

> Ian Collins <ian-...@hotmail.com> wrote:
>> 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).

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>
--
Ben.

pete

unread,
Mar 28, 2010, 9:44:16 AM3/28/10
to
Mark Hobley wrote:

> int dynalloc(struct bufstru *buffer);
>
> buffer is a structure

buffer is a pointer.

(*buffer) is a structure.

--
pete

Mark Hobley

unread,
Mar 31, 2010, 4:58:22 PM3/31/10
to
Mark Hobley <markh...@hotpop.donottypethisbit.com> wrote:
> 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.)

Morris Keesan

unread,
Mar 31, 2010, 5:44:00 PM3/31/10
to

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.

--
Morris Keesan -- mke...@post.harvard.edu

Ben Bacarisse

unread,
Mar 31, 2010, 5:55:58 PM3/31/10
to
markh...@hotpop.donottypethisbit.com (Mark Hobley) writes:

> Mark Hobley <markh...@hotpop.donottypethisbit.com> wrote:
>> 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 */

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.

> (I am using C89 if that matters.)

--
Ben.

Keith Thompson

unread,
Mar 31, 2010, 5:57:41 PM3/31/10
to
"Morris Keesan" <mke...@post.harvard.edu> writes:
[...]

> 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.)

0 new messages