Portability regarding sizeof() function

K

Keith Thompson

pete said:
3.1.2.1 is for the last C89 public draft.

I think Richard H has the offical ANSI C89 standard, not a public
draft.
I think it is important to state that this is not a C99ism.

Nobody implied that it was specific to C99.
The relevant distinction in the below quote,
is "declarator" (which is what it says)
versus "definition" (which is where CBFalconer is mistaken).

ISO/IEC 9899: 1990
6.1.2.1 Scopes of identifiers

Any other identifier has
scope that begins just after the completion of its declarator.

Richard already cited that, though indirectly. He mentioned 3.1.2.1;
section 3 of the 1989 ANSI C standard became section 6 of the 1990 ISO
C standard.
 
K

Keith Thompson

I was going to say, your code is similar to

#include <stdio.h>
int main(void)
{
{ int i = 42; }
{ int j; printf( "%d\n", j ); }
return 0;
}

Yes, but not intentionally so.

Here's a program that, unless I've missed something, actually
illustrates the point I was trying to make:

#include <stdio.h>
int main(void)
{
int i = 0;

LOOP: ;

int *foo_addr;
if (i == 1) {
printf("foo isn't visible yet, but its value is %d\n",
*foo_addr);
}
int foo = 42;
if (i == 0) {
foo_addr = &foo;
}

if (i++ == 0) goto LOOP;

return 0;
}

By using a goto rather than a for loop, I avoid introducing a new
block. The loop executes twice without entering or leaving an outer
block. The lifetime of foo starts at the opening '{' of main and ends
when the "return 0:" is executed, but its visibility starts after the
identifer "foo" in the declaration. By using a goto to branch back to
an earlier point in the block, we reach a pointer where foo exists and
we can access it, but its name is not visible.

I do not claim that this is useful.
 
C

CBFalconer

Ben said:
That is not so. I can't find the place where the standard states
that an identifier is defined from the declarator onwards, but
that has always been my understanding. I.e. even

That's the point. The declaration statement isn't complete until
the semicolon is reached. If you separate it, no problem

struct tm *t;
...
m = malloc(sizeof *t);
 
C

CBFalconer

Keith said:
Yes, it does work (though it took me a while to find the section in
the standard that proves it).

The object exists even before the declaration is reached. C99 6.2.4p4-5:

An object whose identifier is declared with no linkage and without
the storage-class specifier static has _automatic storage
duration_.

For such an object that does not have a variable length array
type, its lifetime extends from entry into the block with which it
is associated until execution of that block ends in any way.

Does that suffice? The identifier t need not even be entered in
the symbol table until the semi is read, according to me. If that
is so sizeof has to look it up to find its size, and it isn't
there. I see mp reason to prevent the compiler reading the
complete statement, up to the semi, before acting on any of it.
 
C

CBFalconer

Richard said:
CBFalconer said:

How do you reconcile your opinion with what the Standard says in
3.1.2.1 of C89 (or 6.2.1(4) of C99), given that the Standard's
take on the matter appears to be diametrically opposite to yours?

That seems (to me) to define the end of the scope. I am worrying
about the start. I don't see how that can precede reading the
statement involved.

[#4] Every other identifier has scope determined by the
placement of its declaration (in a declarator or type
specifier). If the declarator or type specifier that
declares the identifier appears outside of any block or list
of parameters, the identifier has file scope, which
terminates at the end of the translation unit. If the
declarator or type specifier that declares the identifier
appears inside a block or within the list of parameter
declarations in a function definition, the identifier has
block scope, which terminates at the end of the associated
block. If the declarator or type specifier that declares
the identifier appears within the list of parameter
declarations in a function prototype (not part of a function
definition), the identifier has function prototype scope,
which terminates at the end of the function declarator. If
an identifier designates two different entities in the same
name space, the scopes might overlap. If so, the scope of
one entity (the inner scope) will be a strict subset of the
scope of the other entity (the outer scope). Within the
inner scope, the identifier designates the entity declared
in the inner scope; the entity declared in the outer scope
is hidden (and not visible) within the inner scope.
 
C

CBFalconer

Ben said:
The last sentence of 6.2.1(7) seems to be the operative one.

It is a shame that the common case is documented as the exception at
the end of a paragraph. I'd prefer a new paragraph for it, but that
would require more words (but I say that only because I failed
to notice it on more than one reading).

That says:

[#7] Structure, union, and enumeration tags have scope that
begins just after the appearance of the tag in a type
specifier that declares the tag. Each enumeration constant
has scope that begins just after the appearance of its
defining enumerator in an enumerator list. Any other
identifier has scope that begins just after the completion
of its declarator.

Now the question is "where is the completion of its declarator". I
am still voting for the final semi. And, is this a "structure,
union, and enumeration tag"?.
 
K

Keith Thompson

Richard Heathfield said:
Keith Thompson said:
pete said:
Richard Heathfield wrote: [...]
How do you reconcile your opinion with what the Standard says in
3.1.2.1 of C89 (or 6.2.1(4) of C99), given that the Standard's
take on the matter appears to be diametrically opposite to
yours?

3.1.2.1 is for the last C89 public draft.

I think Richard H has the offical ANSI C89 standard, not a public
draft.

Actually, I don't. But I'd be surprised if they changed the
numbering between C89 (draft) and C89 (final). I know they /did/
change the numbering for C90. If I had a copy of C90, I'd cite it.
It is because I don't that I have to make do with the draft (which
is why I always mention C89 rather than C90 when citing therefrom).

I *think* ANSI C89 sections 3 and 4 were turned into ISO C90 sections
6 and 7, respectively, with no changes in the subsection numbering.
At least for the language and library sections, it might be worth
mentioning that when you post C89 citations, since it seems that more
people have C90 than C89 documents.

BTW, it looks like I have a pre-ANSI draft as well; I downloaded it
from <http://flash-gordon.me.uk/ansi.c.txt>.

[...]
 
K

Keith Thompson

Keith Thompson said:
By using a goto rather than a for loop, I avoid introducing a new
block. The loop executes twice without entering or leaving an outer
block. The lifetime of foo starts at the opening '{' of main and ends
when the "return 0:" is executed, but its visibility starts after the
identifer "foo" in the declaration. By using a goto to branch back to
an earlier point in the block, we reach a pointer where foo exists and
we can access it, but its name is not visible.

I meant "we reach a point", not "we reach a pointer". (Somehow, when
I've typed "point", my fingers just keep going and type "er".)
 
K

Keith Thompson

CBFalconer said:
Does that suffice? The identifier t need not even be entered in
the symbol table until the semi is read, according to me. If that
is so sizeof has to look it up to find its size, and it isn't
there. I see mp reason to prevent the compiler reading the
complete statement, up to the semi, before acting on any of it.

No, that doesn't suffice.

What does suffice is the *rest of my article*, which you didn't quote,
in which I cite and quote the wording in the standard that
definitively answers the question.

C99 6.2.1p7

Sheesh!
 
K

Keith Thompson

CBFalconer said:
That's the point. The declaration statement isn't complete until
the semicolon is reached. If you separate it, no problem

struct tm *t;
...
m = malloc(sizeof *t);

You are mistaken. Read my other recent followup. Please read it all
the way to the end.

Or just read C99 6.2.1p7, particularly the last sentence.

Please note that the words "declarator" and "declaration" are
distinct, and that there's no such thing as a "declaration statement".
 
M

Mark Wooding

Ben Bacarisse said:
[The reason I am so sure about what compilers used to do is not a
stellar one; I used to like to write code like this:

char buffer[SOME_SIZE], *bp = buffer;

when I needed some space and a pointer into it. I would never do that
now, of course!]

Why not? It looks perfectly good to me. (I'm assuming that you have
some way of proving that subsequent code doesn't write beyond the bounds
of your buffer, of course, but you seem pretty competent.)

-- [mdw]
 
B

Ben Bacarisse

CBFalconer said:
Ben said:
The last sentence of 6.2.1(7) seems to be the operative one.

It is a shame that the common case is documented as the exception at
the end of a paragraph. I'd prefer a new paragraph for it, but that
would require more words (but I say that only because I failed
to notice it on more than one reading).

That says:

[#7] Structure, union, and enumeration tags have scope that
begins just after the appearance of the tag in a type
specifier that declares the tag. Each enumeration constant
has scope that begins just after the appearance of its
defining enumerator in an enumerator list. Any other
identifier has scope that begins just after the completion
of its declarator.

Now the question is "where is the completion of its declarator". I
am still voting for the final semi.

A declarator is syntactic form defined, quite rigorously, by the
syntax in the standard. In you example the declarator is '*t'.
And, is this a "structure,
union, and enumeration tag"?.

No, it is the last sentence that applies.
 
B

Ben Bacarisse

Mark Wooding said:
Ben Bacarisse said:
[The reason I am so sure about what compilers used to do is not a
stellar one; I used to like to write code like this:

char buffer[SOME_SIZE], *bp = buffer;

when I needed some space and a pointer into it. I would never do that
now, of course!]

Why not? It looks perfectly good to me. (I'm assuming that you have
some way of proving that subsequent code doesn't write beyond the bounds
of your buffer, of course, but you seem pretty competent.)

I was not being serious. I had a smiley but I changed it to an
exclamation mark because I am not keen on them. I think I got the
tone wrong -- I was aiming for humorous faux contrition.

My impression is that the people most likely to argue style are those
that oppose even char *a, *b; so I suspected that mixing declaratror
forms might be even more of red rag.

When unconstrained by external factors, I favour a style that is
rather minimal. I am very happy to have multiple declarators in a
declaration (it reinforces that the base type is the same); I hate
having {}s round a single statement to the extent of writing

if (some_problem())
return *error_code = SOME_PROBLEM, NULL;

and I don't initialise variables whose value won't be used (I really
miss BCPL's ? expression than means "I don't care"). When I was half
my age, I'd have argued that these were all good, and everyone should
do the same!
 
C

CBFalconer

Ben said:
CBFalconer said:
Ben said:
CBFalconer said:
James Kuyper wrote:

... snip ...

Appropriate use of sizeof is essential to writing portable code.
Example:
struct tm *t = malloc(sizeof *t);

Would you care to suggest a more portable way of doing that which
doesn't involve use of the sizeof operator?

Inappropriate use of sizeof can be dangerous, but then so can
inappropriate use of just about any other feature of C.

Nit. I don't think that works. When sizeof is executed t has not
yet been defined. I think it awaits the final semi.

How do you reconcile your opinion with what the Standard says in
3.1.2.1 of C89 (or 6.2.1(4) of C99), given that the Standard's take
on the matter appears to be diametrically opposite to yours?

The last sentence of 6.2.1(7) seems to be the operative one.

It is a shame that the common case is documented as the exception at
the end of a paragraph. I'd prefer a new paragraph for it, but that
would require more words (but I say that only because I failed
to notice it on more than one reading).

That says:

[#7] Structure, union, and enumeration tags have scope that
begins just after the appearance of the tag in a type
specifier that declares the tag. Each enumeration constant
has scope that begins just after the appearance of its
defining enumerator in an enumerator list. Any other
identifier has scope that begins just after the completion
of its declarator.

Now the question is "where is the completion of its declarator". I
am still voting for the final semi.

A declarator is syntactic form defined, quite rigorously, by the
syntax in the standard. In you example the declarator is '*t'.
And, is this a "structure, union, and enumeration tag"?.

No, it is the last sentence that applies.

Alright, thanks. In my defense I said "I don't think that works.".
 
J

James Kuyper

CBFalconer said:
Alright, thanks. In my defense I said "I don't think that works.".

Yes, you did. But you ended up looking more foolish than you would have
if you had checked whether it was correct before expressing that guess.

You repeatedly defended your point of view without bothering to read the
"last sentence" referred to above, and without bothering to check how
the standard actually defines what a declarator is. You should
definitely do more thinking before you post.
 
F

Flash Gordon

Richard said:
Flash Gordon said:


Like I said, I wasn't absolutely certain. :)

I wasn't complaining, only clarifying :)

One important point is that the URL Keith gave might change at some
point, assuming I ever get around to setting up a site properly!
Anyway, I've just
grabbed your version and diff'd it with mine, and they're
identical, which is a bit of a relief (I have a bad habit of
reading the Standard with vim, rather than less).

I use vim a lot as well, although not on the standard. It's a real pain
when I find it isn't installed! Fortunately I now do the builds for our
customers now, so all the tools I want are always installed no new
machines :)
 
S

squeamz

Flash Gordon said:



Like I said, I wasn't absolutely certain. :)  Anyway, I've just
grabbed your version and diff'd it with mine, and they're
identical, which is a bit of a relief (I have a bad habit of
reading the Standard with vim, rather than less).

Why is that a bad habit? Just curious.
 

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,743
Messages
2,569,478
Members
44,898
Latest member
BlairH7607

Latest Threads

Top