question about 2.6 in the faq | | |
I was confused about part 2.6 in the comp.lang.c. FAQ.
2.6 ... <cut>
Another possibility is to declare the variable-size element very
large, rather than very small; in the case of the above example:
...
char namestr[MAXSIZE];
where MAXSIZE is larger than any name which will be stored.
However, it looks like this technique is disallowed by a strict
interpretation of the Standard as well. Furthermore, either of
these "chummy" structures must be used with care, since the
programmer knows more about their size than the compiler does.
I thought it was valid to have arrays of characters in a struct. Am I
missing
something? I realize the intent of the FAQ was to explain how not to
simulate
variable-length arrays.
Thanks for any explanation,
Mick | | | | re: question about 2.6 in the faq
On Oct 20, 9:44 pm, myheartinamerica <myheartinamer...@gmail.com>
wrote: Quote:
I was confused about part 2.6 in the comp.lang.c. FAQ.
>
2.6 ... <cut>
Another possibility is to declare the variable-size element very
large, rather than very small; in the case of the above example:
>
...
char namestr[MAXSIZE];
>
where MAXSIZE is larger than any name which will be stored.
However, it looks like this technique is disallowed by a strict
interpretation of the Standard as well. Furthermore, either of
these "chummy" structures must be used with care, since the
programmer knows more about their size than the compiler does.
>
I thought it was valid to have arrays of characters in a struct. Am I
missing something?
You can have arrays in structs.
The reason the FAQ says this is not valid is because the context is
close to this
char (*p)[42] = malloc(30);
if(p == NULL) return 0;
strcpy(p[0], "hello world");
puts(p[0]);
This will probably compile and "work" as expected by any C
implementation (including the right headers, main, et cetera).
However, p[0] is a char[42]; we've only allocated for a char[30].
Strictly speaking, using p[0] in any way invokes undefined behavior,
just like using a pointer to any object where not enough memory for
that object is allocated is UB. | | | | re: question about 2.6 in the faq
myheartinamerica <myheartinamerica@gmail.comwrites: Quote:
I was confused about part 2.6 in the comp.lang.c. FAQ.
>
2.6 ... <cut>
Another possibility is to declare the variable-size element very
large, rather than very small; in the case of the above example:
>
...
char namestr[MAXSIZE];
>
where MAXSIZE is larger than any name which will be stored.
However, it looks like this technique is disallowed by a strict
interpretation of the Standard as well. Furthermore, either of
these "chummy" structures must be used with care, since the
programmer knows more about their size than the compiler does.
>
>
I thought it was valid to have arrays of characters in a struct. Am I
missing
something? I realize the intent of the FAQ was to explain how not to
simulate
variable-length arrays.
If you'll look at the immediately following code, the idea is to
allocate *less* than the size of the struct, on the assumption that
you'll be ok if you don't use array elements beyond the allocated
size.
Speaking of variable length, it looks like you're writing long lines
and then something is wrapping them; the result is alternating long
and short lines, which can be difficult to read. If you'll keep your
lines below about 70 columns in the first place, this shouldn't
happen.
Compare: Quote:
I thought it was valid to have arrays of characters in a struct. Am I
missing
something? I realize the intent of the FAQ was to explain how not to
simulate
variable-length arrays.
versus: Quote:
I thought it was valid to have arrays of characters in a struct. Am
I missing something? I realize the intent of the FAQ was to explain
how not to simulate variable-length arrays.
--
Keith Thompson (The_Other_Keith) kst-u@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" | | | | re: question about 2.6 in the faq
In article
<356fc94a-85f8-4166-95c1-432e66d2decb@s1g2000prg.googlegroups.com>, vippstar@gmail.com wrote: Quote:
On Oct 20, 9:44 pm, myheartinamerica <myheartinamer...@gmail.com>
wrote: Quote:
I was confused about part 2.6 in the comp.lang.c. FAQ.
2.6 ... <cut>
Another possibility is to declare the variable-size element very
large, rather than very small; in the case of the above example:
...
char namestr[MAXSIZE];
where MAXSIZE is larger than any name which will be stored.
However, it looks like this technique is disallowed by a strict
interpretation of the Standard as well. Furthermore, either of
these "chummy" structures must be used with care, since the
programmer knows more about their size than the compiler does.
I thought it was valid to have arrays of characters in a struct. Am I
missing something?
>
You can have arrays in structs.
The reason the FAQ says this is not valid is because the context is
close to this
>
char (*p)[42] = malloc(30);
if(p == NULL) return 0;
strcpy(p[0], "hello world");
puts(p[0]);
>
This will probably compile and "work" as expected by any C
implementation (including the right headers, main, et cetera).
However, p[0] is a char[42]; we've only allocated for a char[30].
Strictly speaking, using p[0] in any way invokes undefined behavior,
just like using a pointer to any object where not enough memory for
that object is allocated is UB.
Just to give a more obviously UB example that as you hint at, this
allocates space for only the first int in the struct:
struct S { int i, j; };
S* s = malloc( sizeof (int) );
s->i = 1234; // UB
printf( "%d\n", s->i ); // UB
Perhaps one justification a compiler could provide is that S has a
stricter alignment requirement than int, and since the size passed to
malloc is less than sizeof (S), it isn't required to align the memory
sufficiently for S. | | | | re: question about 2.6 in the faq
blargg wrote: Quote:
>
Just to give a more obviously UB example that as you hint at, this
allocates space for only the first int in the struct:
>
struct S { int i, j; };
>
struct Quote:
S* s = malloc( sizeof (int) );
s->i = 1234; // UB
printf( "%d\n", s->i ); // UB
>
Perhaps one justification a compiler could provide is that S has a
stricter alignment requirement than int, and since the size passed to
malloc is less than sizeof (S), it isn't required to align the memory
sufficiently for S.
There was a huge debate about this in c.l.c. about fifteen years
ago, and the eventual consensus was that all alignment requirements
must be met even if their possible violation is untestable.
But there's another problem, not involving alignment. Since the
compiler "knows" that `s' is either NULL or points to a `struct S'
object, the compiler is free to generate code that accesses `s->j'
even if you and I can't see any good reason for it to do so. If
the memory that ought to hold `s->j' doesn't actually exist, the
consequences are unpredictable. (Yes, I once debugged just such a
situation: The details were a little different, but when a "short"
struct instance happened to fall close to the end of a memory page
and the compiler decided to pre-fetch a non-existent field several
lines before the program wanted to use it, all Hell broke loose.)
-- Eric.Sosman@sun.com | | | | re: question about 2.6 in the faq
In article <1224538652.646588@news1nwk>, Eric Sosman <Eric.Sosman@sun.com>
wrote: Quote:
blargg wrote: Quote:
Just to give a more obviously UB example that as you hint at, this
allocates space for only the first int in the struct:
struct S { int i, j; };
struct Quote:
S* s = malloc( sizeof (int) );
s->i = 1234; // UB
printf( "%d\n", s->i ); // UB
Perhaps one justification a compiler could provide is that S has a
stricter alignment requirement than int, and since the size passed to
malloc is less than sizeof (S), it isn't required to align the memory
sufficiently for S.
>
There was a huge debate about this in c.l.c. about fifteen years
ago, and the eventual consensus was that all alignment requirements
must be met even if their possible violation is untestable.
Not sure what you mean "even if their possible violation is untestable".
Are you saying that malloc(1) must align for example to 8 bytes on
platforms where double has an 8-byte alignment requirement, even though a
sizeof(double)>1 on such a platform? About the only useful consequence of
that seems to be that you could do
double* d = malloc(1);
char* c = (char*) d;
// use *c...
free( c ); // well-defined Quote:
But there's another problem, not involving alignment. Since the
compiler "knows" that `s' is either NULL or points to a `struct S'
object, the compiler is free to generate code that accesses `s->j'
even if you and I can't see any good reason for it to do so. If
the memory that ought to hold `s->j' doesn't actually exist, the
consequences are unpredictable. (Yes, I once debugged just such a
situation: The details were a little different, but when a "short"
struct instance happened to fall close to the end of a memory page
and the compiler decided to pre-fetch a non-existent field several
lines before the program wanted to use it, all Hell broke loose.)
Your example sounds more like this:
short* p = <logical address that's not yet valid to access>;
// provide physical backing for address by messing with page tables
// ...
// now access memory
*p = 1234;
where the compiler is free to move the store to p earlier (and thus cause
a crash), since p isn't declared to point to a volatile type as it should
be. | | | | re: question about 2.6 in the faq
blargg wrote: Quote:
In article <1224538652.646588@news1nwk>, Eric Sosman <Eric.Sosman@sun.com>
wrote:
> Quote:
>blargg wrote: Quote:
>>Just to give a more obviously UB example that as you hint at, this
>>allocates space for only the first int in the struct:
>>>
>> struct S { int i, j; };
>>>
> struct Quote:
>> S* s = malloc( sizeof (int) );
>> s->i = 1234; // UB
>> printf( "%d\n", s->i ); // UB
>>>
>>Perhaps one justification a compiler could provide is that S has a
>>stricter alignment requirement than int, and since the size passed to
>>malloc is less than sizeof (S), it isn't required to align the memory
>>sufficiently for S.
> There was a huge debate about this in c.l.c. about fifteen years
>ago, and the eventual consensus was that all alignment requirements
>must be met even if their possible violation is untestable.
>
Not sure what you mean "even if their possible violation is untestable".
Are you saying that malloc(1) must align for example to 8 bytes on
platforms where double has an 8-byte alignment requirement, even though a
sizeof(double)>1 on such a platform? About the only useful consequence of
that seems to be that you could do
>
double* d = malloc(1);
char* c = (char*) d;
// use *c...
free( c ); // well-defined
Yes, that's my report of the consensus. The fragment you
show has well-defined behavior (assuming "use *c" makes proper
provision for the case `d == NULL'). Note that "the fragment
works" is a little weaker than the consensus opinion: All it
shows is that malloc() returns a pointer that can be converted
to `double*' without loss of information. My own take on the
consensus was along the lines of "That which has no observable
consequences does not exist" -- the philosophy majors are welcome
to shred me on this one -- but I have no desire to reawaken the
sterile argument, just to report its existence and its outcome. Quote: Quote:
> But there's another problem, not involving alignment. Since the
>compiler "knows" that `s' is either NULL or points to a `struct S'
>object, the compiler is free to generate code that accesses `s->j'
>even if you and I can't see any good reason for it to do so. If
>the memory that ought to hold `s->j' doesn't actually exist, the
>consequences are unpredictable. (Yes, I once debugged just such a
>situation: The details were a little different, but when a "short"
>struct instance happened to fall close to the end of a memory page
>and the compiler decided to pre-fetch a non-existent field several
>lines before the program wanted to use it, all Hell broke loose.)
>
Your example sounds more like this:
>
short* p = <logical address that's not yet valid to access>;
>
// provide physical backing for address by messing with page tables
// ...
>
// now access memory
*p = 1234;
>
where the compiler is free to move the store to p earlier (and thus cause
a crash), since p isn't declared to point to a volatile type as it should
be.
Since C provides no mechanism to produce a "logical address
that's not yet valid to access," I'm not sure what to make of
your example. The bug I debugged (with two other people, the
three of us contributing different skills to the job) did not
involve the setting of any pointer to an invalid address. Rather,
the pointer was to a perfectly valid address -- but not to an
address that was valid for a full-fledged `struct S'.
--
Eric Sosman esosman@ieee-dot-org.invalid | | | | re: question about 2.6 in the faq
On Oct 20, 2:08*pm, Keith Thompson <ks...@mib.orgwrote: Quote:
Speaking of variable length, it looks like you're writing long lines
and then something is wrapping them; the result is alternating long
and short lines, which can be difficult to read. *If you'll keep your
lines below about 70 columns in the first place, this shouldn't
happen.
>
Compare:
> Quote:
I thought it was valid to have arrays of characters in a struct. Am I
missing
something? I realize the intent of the FAQ was to explain how not to
simulate
variable-length arrays.
>
versus:
> Quote:
I thought it was valid to have arrays of characters in a struct. Am
I missing something? I realize the intent of the FAQ was to explain
how not to simulate variable-length arrays.
I wholeheartedly agree that it was unreadable. I wrote my response in
Vim wrapped at 80 columns. Then I pasted it into the web interface of
Google Groups, which doesn't seem to show you where it will wrap.
Google Groups lets you compose lines that are wrapped by the size of
the input box. If I resize my browser window, it resizes where the
lines are wrapped.
While I appreciate the convenience of Google Groups, I question its
impact on Usenet readability and quality.
Anyways, I intend this to be the last message I write from the web
interface.
Thanks for your response,
Mick Beaver |  | | | | /bytes/about
We are a network of experts and professionals in IT and software development that help one another with answers to tough questions and share insights.
Get the best answers to your questions from over 226,501 network members.
|