sizeof extern arrays

K

Kieran Simkin

I have in my project in main.c a number of arrays defined like this (outside
of any functions):
char muser[256], mpass[256];
I'm declaring them in a number of other .c files (inside functions) like
this:
extern char muser[], mpass[];

However, in one of these functions outside of main.c I need to snprintf into
these buffers. Usually when using snprintf I call it like this:
snprintf(muser, sizeof muser, "text");
My problem is that sizeof does not work on extern arrays declared as above -
GCC returns the following error:
config.c:41: sizeof applied to an incomplete type

What's the best solution to this problem? I'm assuming it's valid to specify
an array's size when declaring it with extern, but I'd rather not have magic
numbers scattered all over my source files. Is there any way I can use
sizeof or similar on externally defined arrays without specifying array
dimensions in each source file?

Thanks.

~Kieran Simkin
Digital Crocus
http://digital-crocus.com/
 
E

Eric Sosman

Kieran said:
I have in my project in main.c a number of arrays defined like this (outside
of any functions):
char muser[256], mpass[256];
I'm declaring them in a number of other .c files (inside functions) like
this:
extern char muser[], mpass[];

However, in one of these functions outside of main.c I need to snprintf into
these buffers. Usually when using snprintf I call it like this:
snprintf(muser, sizeof muser, "text");
My problem is that sizeof does not work on extern arrays declared as above -
GCC returns the following error:
config.c:41: sizeof applied to an incomplete type

What's the best solution to this problem? I'm assuming it's valid to specify
an array's size when declaring it with extern, but I'd rather not have magic
numbers scattered all over my source files. Is there any way I can use
sizeof or similar on externally defined arrays without specifying array
dimensions in each source file?

The best solution is the same as for any other identifier
with external linkage: Write the declaration once in a header
file, and #include that header file in each source module that
needs access to the identifiers. It may not seem obvious, but
the source file that actually *defines* the identifier should
also #include the header.

/* simkin.h */
extern char muser[256];
extern char mpass[256];

/* simkin.c */
#include "simkin.h"
char muser[256];
char mpass[256];

/* simkin2.c */
#include <stdio.h>
#include "simkin.h"
void print_them(void) {
printf ("muser = %s\n", muser);
printf ("mpass = %s\n", mpass);
}

One other observation: data identifiers with external
linkage ("global variables") should be used sparingly. Sad
experience has demonstrated that programs with many global
variables are much harder to maintain, extend, and debug
than programs with few of them. From the names you have
given your variables, I strongly suspect that these data
objects are *not* good candidates for globalization.

Proceed At Your Own Risk.
 
C

Chris Torek

char muser[256], mpass[256]; [and in others]
extern char muser[], mpass[];

However, in one of these functions outside of main.c I need to snprintf into
these buffers. Usually when using snprintf I call it like this:
snprintf(muser, sizeof muser, "text");
My problem is that sizeof does not work on extern arrays declared as above -
GCC returns the following error:
config.c:41: sizeof applied to an incomplete type

What's the best solution to this problem?[/QUOTE]

What's the "best" way to get across a lake -- boat, bridge, or going
around the outside?

There are lots of options, none clearly "best".

Here is one option:

main.c:
char muser[256];
size_t muser_size = sizeof muser;
...

other.c:
extern char muser[];
extern size_t muser_size;
...
val = snprintf(muser, muser_size, "text");

Here is another:

main.c:
#include "user.h"
char muser[MUSER_SIZE];
...

other.c:
#include "user.h"
...
val = snprintf(muser, MUSER_SIZE, "text"); /* or sizeof */

user.h:
#define MUSER_SIZE 256
extern char muser[MUSER_SIZE];

Yet another is to have a user.h as above, but use something like:

DECLARE_OR_DEFINE char muser[256];

and make sure that precisely one .c file defines "DECLARE_OR_DEFINE"
as the empty string, while the rest define it as "extern". For
instance, put:

#ifndef DECLARE_OR_DEFINE
#define DECLARE_OR_DEFINE extern /* default is "declare" */
#endif

near the top of user.h, and then have main.c do:

#define DECLARE_OR_DEFINE /* nothing, i.e., define */
#include "user.h"

This last solution uses the least redundancy, but I personally prefer
the others.
 
K

Kieran Simkin

Ah perfect, that's exactly the kind of solution I was looking for.
I've read in the c.l.c FAQ that using externally linked variables a lot
isn't a good idea. Currently what I'm doing is defining a few buffers which
hold various config options (like the mysql username and password the
program should be using etc). These config options are read in from a file
and then declared with extern individually in each of the source files that
require them. Adding a new config option is quite easy because I just have
to make a modification to my config file reading function, define a buffer
to store it in and declare the buffer I wish to use in the new source file
I'm writing.
I've been thinking about replacing this with a linked list containing all
the config options in a struct like this:

struct confignode {
char name[256];
char value[256];
struct confignode *next;
};

However, then every time I wanted to use a config option I would have to
call a function to traverse the list which in real terms probably wouldn't
mean a significant performance hit, but it seems wasteful. Any suggestions
on a better way to hold config options without using externally linked
variables?


~Kieran Simkin
Digital Crocus
http://digital-crocus.com/

Eric Sosman said:
Kieran said:
I have in my project in main.c a number of arrays defined like this (outside
of any functions):
char muser[256], mpass[256];
I'm declaring them in a number of other .c files (inside functions) like
this:
extern char muser[], mpass[];

However, in one of these functions outside of main.c I need to snprintf into
these buffers. Usually when using snprintf I call it like this:
snprintf(muser, sizeof muser, "text");
My problem is that sizeof does not work on extern arrays declared as above -
GCC returns the following error:
config.c:41: sizeof applied to an incomplete type

What's the best solution to this problem? I'm assuming it's valid to specify
an array's size when declaring it with extern, but I'd rather not have magic
numbers scattered all over my source files. Is there any way I can use
sizeof or similar on externally defined arrays without specifying array
dimensions in each source file?

The best solution is the same as for any other identifier
with external linkage: Write the declaration once in a header
file, and #include that header file in each source module that
needs access to the identifiers. It may not seem obvious, but
the source file that actually *defines* the identifier should
also #include the header.

/* simkin.h */
extern char muser[256];
extern char mpass[256];

/* simkin.c */
#include "simkin.h"
char muser[256];
char mpass[256];

/* simkin2.c */
#include <stdio.h>
#include "simkin.h"
void print_them(void) {
printf ("muser = %s\n", muser);
printf ("mpass = %s\n", mpass);
}

One other observation: data identifiers with external
linkage ("global variables") should be used sparingly. Sad
experience has demonstrated that programs with many global
variables are much harder to maintain, extend, and debug
than programs with few of them. From the names you have
given your variables, I strongly suspect that these data
objects are *not* good candidates for globalization.

Proceed At Your Own Risk.
 
E

Emmanuel Delahaye

Kieran Simkin said:
I have in my project in main.c a number of arrays defined like this
(outside of any functions):
char muser[256], mpass[256];
I'm declaring them in a number of other .c files (inside functions) like
this:
extern char muser[], mpass[];

Do it the reverse way :

The definitions (.c):

#include "the_declarations.h"
char muser[], mpass[];

The declarations (.h) :

extern char muser[256], mpass[256];

Simple, safe and portable.
 
E

Emmanuel Delahaye

In 'comp.lang.c' said:
/* simkin.h */
extern char muser[256];
extern char mpass[256];

/* simkin.c */
#include "simkin.h"
char muser[256];
char mpass[256];

Considering that the size is gven in the declaration, isn't is possible to
get rid of the size here ?

char muser[];
char mpass[];

it simplifies the maintenance.
 
M

Mike Wahler

Kieran Simkin said:
Ah perfect, that's exactly the kind of solution I was looking for.
I've read in the c.l.c FAQ that using externally linked variables a lot
isn't a good idea. Currently what I'm doing is defining a few buffers which
hold various config options (like the mysql username and password the
program should be using etc). These config options are read in from a file
and then declared with extern individually in each of the source files that
require them. Adding a new config option is quite easy because I just have
to make a modification to my config file reading function, define a buffer
to store it in and declare the buffer I wish to use in the new source file
I'm writing.
I've been thinking about replacing this with a linked list containing all
the config options in a struct like this:

struct confignode {
char name[256];
char value[256];
struct confignode *next;
};

However, then every time I wanted to use a config option I would have to
call a function to traverse the list which in real terms probably wouldn't
mean a significant performance hit, but it seems wasteful. Any suggestions
on a better way to hold config options without using externally linked
variables?

You could malloc() the memory for the data, and pass
around a pointer to it as function argument(s).

If you'll be using a linked list, you'll be malloc'ing
anyway.

-Mike
 
D

Dan Pop

In said:
Kieran said:
I have in my project in main.c a number of arrays defined like this (outside
of any functions):
char muser[256], mpass[256];
I'm declaring them in a number of other .c files (inside functions) like
this:
extern char muser[], mpass[];

However, in one of these functions outside of main.c I need to snprintf into
these buffers. Usually when using snprintf I call it like this:
snprintf(muser, sizeof muser, "text");
My problem is that sizeof does not work on extern arrays declared as above -
GCC returns the following error:
config.c:41: sizeof applied to an incomplete type

What's the best solution to this problem? I'm assuming it's valid to specify
an array's size when declaring it with extern, but I'd rather not have magic
numbers scattered all over my source files. Is there any way I can use
sizeof or similar on externally defined arrays without specifying array
dimensions in each source file?

The best solution is the same as for any other identifier
with external linkage: Write the declaration once in a header
file, and #include that header file in each source module that
needs access to the identifiers. It may not seem obvious, but
the source file that actually *defines* the identifier should
also #include the header.

/* simkin.h */
extern char muser[256];
extern char mpass[256];

/* simkin.c */
#include "simkin.h"
char muser[256];
char mpass[256];

/* simkin2.c */
#include <stdio.h>
#include "simkin.h"
void print_them(void) {
printf ("muser = %s\n", muser);
printf ("mpass = %s\n", mpass);
}

OTOH, if the magic value 256 changes, you want to minimise the number of
places that need editing. So, it's better to define one or two macros
(two if the sizes of the two arrays are unrelated) in simkin.h and use
them in both simkin.h and simkin.c. This approach also completely removes
any need for the sizeof operator, BTW.

/* simkin.h */
#define MUSER_SIZE 256
#define MPASS_SIZE 256

extern char muser[MUSER_SIZE];
extern char mpass[MPASS_SIZE];

Dan
 

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,755
Messages
2,569,536
Members
45,013
Latest member
KatriceSwa

Latest Threads

Top