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

Declaration statement

61 views
Skip to first unread message

Gattaca

unread,
Mar 9, 2004, 2:28:15 PM3/9/04
to
Are those two declaration statements equivalent ?
char *string;
char string[];

If not what are the differences ?

Thanks for your help.

Joona I Palaste

unread,
Mar 9, 2004, 2:36:10 PM3/9/04
to
Gattaca <gat...@hotmail.com> scribbled the following:

> Thanks for your help.

They are not equivalent at all. The first declares a pointer to a char,
the second won't compile.

--
/-- Joona Palaste (pal...@cc.helsinki.fi) ------------- Finland --------\
\-- http://www.helsinki.fi/~palaste --------------------- rules! --------/
"It's time, it's time, it's time to dump the slime!"
- Dr. Dante

Mike Wahler

unread,
Mar 9, 2004, 2:51:43 PM3/9/04
to

"Gattaca" <gat...@hotmail.com> wrote in message
news:c2l5pd$4l5$1...@news.tiscali.fr...

> Are those two declaration statements equivalent ?

No.

> char *string;
> char string[];
>
> If not what are the differences ?

The first is valid syntax, the second is not.

-Mike


Ed Morton

unread,
Mar 9, 2004, 3:27:38 PM3/9/04
to

Despite the invalid syntax on the second item, I think the question
you're really trying to ask is probably answered in the FAQ. For
example, see http://www.eskimo.com/~scs/C-faq/q6.2.html.

Regards,

Ed.

Jeremy Yallop

unread,
Mar 9, 2004, 5:33:48 PM3/9/04
to
Gattaca wrote:
> Are those two declaration statements equivalent ?
> char *string;
> char string[];

No. However, despite the three unanimously incorrect answers you've
received so far, both are syntactically valid.



> If not what are the differences ?

The short answer is that the first declares a pointer, the second an
array.

The longer answer is that when they appear at file scope they are both
tenatative external declarations. If no other declaration follows
then they both behave as if initialised with `{0}', so the first
declares a pointer, initialised as null, the second an array of one
element, which is initialised to value 0. When they appear at block
scope the first declares an uninitialised pointer and the second is
invalid. Leaving aside struct declarations, etc., the other situation
in which both lines are valid is in old-style function declarations:

int foo(a, b)
char *a;
char b[];
{
}

Here both `a' and `b' are pointers to char, more or less as if you'd
written

int foo(char *a, char b[])
{
}

(the difference being that the second version acts as a prototype).
They can't both appear in the same scope in the same translation unit,
because they declare conflicting types for `string'.

My final comment is that, although the syntax is valid, `string' is
not a valid name for an external identifier: names beginning with
'str' followed by a lower-case letter are reserved for the
implementation.

For more details, see the section 6 of the FAQ.

Jeremy.

Malcolm

unread,
Mar 9, 2004, 6:34:28 PM3/9/04
to

"Gattaca" <gat...@hotmail.com> wrote in message
> char *string;
> char string[];
>
> If not what are the differences ?
>
There's some obscure rule to do with external linkage which means that you
cannot mix syntax if you are declaring string in one file and using it in a
second. For all practical purposes however the forms are identical.


Mike Wahler

unread,
Mar 9, 2004, 6:52:03 PM3/9/04
to

"Jeremy Yallop" <jer...@jdyallop.freeserve.co.uk> wrote in message
news:slrnc4shic...@hehe.cl.cam.ac.uk...

> Gattaca wrote:
> > Are those two declaration statements equivalent ?
> > char *string;
> > char string[];
>
> No. However, despite the three unanimously incorrect answers you've
> received so far, both are syntactically valid.

Not as written.

extern char string[];

... would be OK

Also valid would be 'char string[]' as a function
parameter, but the semicolon precludes that.

I answered in the context given.

-Mike


Jeremy Yallop

unread,
Mar 9, 2004, 6:57:53 PM3/9/04
to
Mike Wahler wrote:
> "Jeremy Yallop" <jer...@jdyallop.freeserve.co.uk> wrote in message
> news:slrnc4shic...@hehe.cl.cam.ac.uk...
>> Gattaca wrote:
>> > Are those two declaration statements equivalent ?
>> > char *string;
>> > char string[];
>>
>> No. However, despite the three unanimously incorrect answers you've
>> received so far, both are syntactically valid.
>
> Not as written.

Sorry, but you're simply wrong. You might like to read my previous
post before replying again. I'm not sure why you're so sure about
this, but you might like to note that this is one aspect in which C
differs from C++.

Jeremy.

Mike Wahler

unread,
Mar 9, 2004, 7:06:34 PM3/9/04
to

"Jeremy Yallop" <jer...@jdyallop.freeserve.co.uk> wrote in message
news:slrnc4smg1...@kaje.cl.cam.ac.uk...

Erm, never mind. Time to take a break! :-)

-Mike


Jon Willeke

unread,
Mar 9, 2004, 7:17:50 PM3/9/04
to
Gattaca wrote:

> Are those two declaration statements equivalent ?
> char *string;
> char string[];
>
> If not what are the differences ?

Peter van der Linden devotes three good chapters to this topic in his
excellent _Expert C Programming_.

Message has been deleted

Gattaca

unread,
Mar 10, 2004, 4:41:36 AM3/10/04
to
Gattaca a écrit :

many thanks to all of you.

Xiangliang Meng

unread,
Mar 10, 2004, 6:18:12 AM3/10/04
to
Thank you for providing so many details here. I try some by using my gcc.
You are right.

Could you explain a little more on why they are OK in a file scope, but the
second is invalid in blocks? What is the difference for the second between
in the file scope and in the block scope?

Thanks a lot.

Cheers,
Xiangliang Meng


"Jeremy Yallop" <jer...@jdyallop.freeserve.co.uk> wrote in message
news:slrnc4shic...@hehe.cl.cam.ac.uk...

Chris Torek

unread,
Mar 10, 2004, 2:48:14 PM3/10/04
to
Regarding:

char *s;
char t[];

as declarations appearing at file and block scope...

In article <news:c2mte5$au4$1...@zcars0v6.ca.nortel.com>


Xiangliang Meng <xiangli...@hotmail.com> writes:
>Could you explain a little more on why they are OK in a file scope, but the
>second is invalid in blocks? What is the difference for the second between
>in the file scope and in the block scope?

At the most important level, the reason is just "because the C
Standards say so". The declaration of "t" above is invalid in
block scope because the rules of the C standard prohibit it; it is
valid in file scope -- and means the same as "char t[1]" if no
other declaration overrides it -- because the rules of the C
Standards say so.

Fundamentally, there is no particular reason it *has* to work this
way, and in the days before the first C standard (ANSI X3.159-1989,
also known as "C89"), different C compilers had different rules.
If you wrote "char t[];" at file scope, some compilers gave you an
error message and refused to compile your code. If the people who
wrote the C89 standard had so chosen, they could have made this an
error. Instead, though, they decided to adopt a series of rules
that give useful results in various cases where pre-C89 compilers
sometime fell short.

In particular, the C89 folks invented (or borrowed) the concept of
a "tentative definition" of a variable. You can "tentatively"
define a variable, which has the useful side effect of telling the
C compiler that it is going to exist sooner or later, so that you
can use the name of the variable. Eventually you also define the
variable "for real", possibly giving it an initial value.

Consider the example of a circular queue data structure:

struct queue {
struct queue *forw, *back;
some_type data;
};

Queues like this often have a "dummy" head node and then zero or
more data nodes. Suppose you want to provide an initial single
data node. How can you define two variables that will point to
each other?

If both variables are to have external linkage (i.e., are "global
variables" in the sense people usually mean by the phrase "global
variables"), you can, even in implementations predating the 1989
C standard, write this code:

extern struct queue initialnode;

struct queue head = {
&initialnode, &initialnode
/* no actual data (dummy head) */
};

struct queue initialnode = {
&head, &head,
INITIAL_DATA
};

The first of these lines announces to the C compiler: "there is a
variable named initialnode, of type struct queue". This announcement
is required in order to provide &initialnode as the initializer
for head.forw and head.back.

But what if, on the other hand, both of these variables are to be
declared "static" (i.e., have internal linkage)? You must write:

static struct queue initialnode;

("static" instead of "extern"). Many pre-C89 C compilers took
this as the *definition* of the variable initialnode, meaning
the same thing as:

static struct queue initialnode = { 0, 0, 0 };

If you follow this with a later:

static struct queue initialnode = {
&head, &head,
INITIAL_DATA
};

you just got an error. You cannot write "extern struct queue
initialnode; ... static struct queue initialnode = { ... };"
either, as this is also an error.

The C89 solution to this problem is "tentative definitions", in
which you simply write the definition with no initializer. A
tentative definition is, in effect, "recorded" at the point of the
definition and "remembered" until a corresponding actual (non-tentative)
definition, or the end of the translation unit:

static struct queue initialnode; /* tentative */
static struct queue head = { &initialnode, &initialnode };
static struct queue initialnode = /* actual */
{ &head, &head, INITIAL_DATA };

char t[]; /* also tentative */

At the end of the translation unit, all the outstanding tentative
definitions become actual definitions, initialized with "= { 0 }".
This means that the declaration for t eventually becomes:

char t[] = { 0 };

which gives t a single element (so that sizeof(t) is 1*sizeof(char),
which is just 1).
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.

Dan Pop

unread,
Mar 11, 2004, 10:16:43 AM3/11/04
to

>Regarding:
>
> char *s;
> char t[];
>
>as declarations appearing at file and block scope...
>
>In article <news:c2mte5$au4$1...@zcars0v6.ca.nortel.com>
>Xiangliang Meng <xiangli...@hotmail.com> writes:
>>Could you explain a little more on why they are OK in a file scope, but the
>>second is invalid in blocks? What is the difference for the second between
>>in the file scope and in the block scope?
>
>At the most important level, the reason is just "because the C
>Standards say so". The declaration of "t" above is invalid in
>block scope because the rules of the C standard prohibit it; it is

^^^^^


>valid in file scope -- and means the same as "char t[1]" if no

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^


>other declaration overrides it -- because the rules of the C

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>Standards say so.

Can I have a chapter and verse for that?

fangorn:~/tmp 458> cat test.c
#include <stdio.h>

char t[];

int main()
{
printf("%d\n", (int)sizeof t);
return 0;
}

fangorn:~/tmp 459> gcc -ansi -pedantic test.c
test.c: In function `main':
test.c:7: error: invalid application of `sizeof' to an incomplete type
test.c: At top level:
test.c:3: warning: array `t' assumed to have one element
fangorn:~/tmp 460> icc test.c
test.c(7): warning #70: incomplete type is not allowed
printf("%d\n", (int)sizeof t);
^

fangorn:~/tmp 461> pgcc test.c
PGC-S-0061-Sizeof dimensionless array required (test.c: 7)
PGC/x86 Linux/x86 3.3-2: compilation completed with severe errors

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: Dan...@ifh.de

Chris Torek

unread,
Mar 11, 2004, 11:19:02 AM3/11/04
to
>In <c2nrd...@enews3.newsguy.com> Chris Torek <nos...@torek.net> writes:
>> char t[];
>>... is

>>valid in file scope -- and means the same as "char t[1]" if no
>>other declaration overrides it -- because the rules of the C
>>Standards say so.

In article <news:c2pvsr$87e$1...@sunnews.cern.ch>


Dan Pop <Dan...@cern.ch> wrote:
>Can I have a chapter and verse for that?

In the old C99 draft I keep lying around, it is 6.7.2, "External
object definitions":

Semantics
... If a translation unit
contains one or more tentative definitions for an
identifier, and the translation unit contains no external
definition for that identifier, then the behavior is exactly
as if the translation unit contains a file scope declaration
of that identifier, with the composite type as of the end of
the translation unit, with an initializer equal to 0.
...
Examples
2. If at the end of the translation unit containing

int i[];

the array i still has incomplete type, the array is
assumed to have one element. This element is
initialized to zero on program startup.

Note that the identifier (i here, t in my example above) refers to
an object with incomplete type that is not completed until the T.U.
has ended, so:

> fangorn:~/tmp 458> cat test.c
> #include <stdio.h>
>
> char t[];
>
> int main()
> {
> printf("%d\n", (int)sizeof t);
> return 0;
> }
>
> fangorn:~/tmp 459> gcc -ansi -pedantic test.c
> test.c: In function `main':
> test.c:7: error: invalid application of `sizeof' to an incomplete type

... this is a required diagnostic.

> test.c: At top level:
> test.c:3: warning: array `t' assumed to have one element

This one is merely gcc being helpful, telling you that (now that
the translation unit has ended) an array is being created after
all, with size 1, which is probably not what you intended.

(It is both somewhat obnoxious and almost entirely useless that
the size of the array is going to become 1 and yet is not known
before the translation unit terminates, so that "sizeof t" is an
error. An array of one element is, of course, no more useful than
an ordinary object whose type is the element-type of the array.
Still, warning about an explicit "T arr[1]" would also be obnoxious
-- it is just the warning about the empty brackets being "backfilled"
with 1 that is helpful.)

Old Wolf

unread,
Mar 11, 2004, 4:13:43 PM3/11/04
to
> >Regarding:
> >
> > char *s;
> > char t[];
> >
> >as declarations appearing at file and block scope...
> >
> >The declaration of "t" above is invalid in
> >block scope because the rules of the C standard prohibit it; it is
> ^^^^^
> >valid in file scope -- and means the same as "char t[1]" if no
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> >other declaration overrides it -- because the rules of the C
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> >Standards say so.
>
> Can I have a chapter and verse for that?

No, but we have GCC warnings to guide us..:)

> char t[];
>
> int main()
> {

You could insert here:
t[0] = 'x';
without error.

> printf("%d\n", (int)sizeof t);
> return 0;
> }
>
> fangorn:~/tmp 459> gcc -ansi -pedantic test.c
> test.c: In function `main':
> test.c:7: error: invalid application of `sizeof' to an incomplete type
> test.c: At top level:
> test.c:3: warning: array `t' assumed to have one element
> fangorn:~/tmp 460> icc test.c
> test.c(7): warning #70: incomplete type is not allowed
> printf("%d\n", (int)sizeof t);
> ^

You can't do 'sizeof' on an incomplete type.

However, in a value context, the name of an array is converted
to a pointer to its first element, which has type (char *)
and is not incomplete, so my assignment above is valid.

As another poster noted, it is very similar to "extern char c[];"
except c[] is not external, and if you do not define c,
the compiler acts as if you had the last line of your file "char c[1];"

Dan Pop

unread,
Mar 12, 2004, 10:27:47 AM3/12/04
to

>>In <c2nrd...@enews3.newsguy.com> Chris Torek <nos...@torek.net> writes:
>>> char t[];
>>>... is
>>>valid in file scope -- and means the same as "char t[1]" if no

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^


>>>other declaration overrides it -- because the rules of the C

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^


>>>Standards say so.
>
>In article <news:c2pvsr$87e$1...@sunnews.cern.ch>
>Dan Pop <Dan...@cern.ch> wrote:
>>Can I have a chapter and verse for that?
>
>In the old C99 draft I keep lying around, it is 6.7.2, "External
>object definitions":
>
> Semantics
> ... If a translation unit
> contains one or more tentative definitions for an
> identifier, and the translation unit contains no external
> definition for that identifier, then the behavior is exactly
> as if the translation unit contains a file scope declaration
> of that identifier, with the composite type as of the end of
> the translation unit, with an initializer equal to 0.
> ...
> Examples
> 2. If at the end of the translation unit containing
>
> int i[];
>
> the array i still has incomplete type, the array is
> assumed to have one element. This element is
> initialized to zero on program startup.
>
>Note that the identifier (i here, t in my example above) refers to
>an object with incomplete type that is not completed until the T.U.
>has ended, so:

This was precisely why I asked a chapter and verse for your *original*
statement underlined above, which is incorrect: char t[] doesn't
mean the same as char t[1] if no other declaration overrides it. The
latter declares a complete type, while the former declares an incomplete
type that becomes complete only at the end of the translation unit, i.e.
when it is too late to be used as a complete type.

Chris Torek

unread,
Mar 12, 2004, 7:31:02 PM3/12/04
to
[snippage, see original article if needed]

In article <news:c2sktj$dou$4...@sunnews.cern.ch>


Dan Pop <Dan...@cern.ch> writes:
>This was precisely why I asked a chapter and verse for your *original*
>statement underlined above, which is incorrect: char t[] doesn't
>mean the same as char t[1] if no other declaration overrides it. The
>latter declares a complete type, while the former declares an incomplete
>type that becomes complete only at the end of the translation unit, i.e.
>when it is too late to be used as a complete type.

I agree that my original wording was not the best (as the meanings
are not 100% identical), but in fact, the object is eventually
declared as having size 1, which means any reference to it elsewhere
must also declare it as having size 1, or as an incomplete type.
That is, if file f1.c says:

char t[];

and file f2.c is to have a line reading:

extern char t[N];

for some integer constant N, then N had better be 1. As far as
f2.c is concerned, the definition in f1.c has the same meaning as
if the brackets were filled with 1.

(Real implementations tend to relax the rules on separate files,
so that if f2.c says "extern char t[42];" the compiler simply
believes the programmer, and sizeof(t) is 42 in f2.c, but at
link-time, the true size of the array is 1. The effect of accessing
elements beyond t[0] is unpredictable. Formally, even accessing
t[0] appears to be undefined behavior here -- but usually it works
fine.)

In other words, when I said "means the same", I meant "to other
translation units", not "within the T.U. in question".

Dan Pop

unread,
Mar 15, 2004, 9:33:41 AM3/15/04
to

>In other words, when I said "means the same", I meant "to other
>translation units", not "within the T.U. in question".

Keep in mind that the rest of us are not mind readers ;-)

0 new messages