# "struct hack" with non-character array[1]

H

#### Hallvard B Furuseth

I seem to remember the "struct hack" is safer if the fake
dynamic array has character type. If that's right, where/why?
Maybe in C99, since the struct hack is undefined in C89? Or
real life implementations, nothing to do with the standard?

That is,
typedef <char or int> T;
struct hack { Foo foo; T dynamic[1]; };
struct hack h = malloc(sizeof *h) + sizeof(T)*n;
.... use h->dynamic[0..n-1] ...;
would be safer with T = char than with T = int.

The C FAQ does not mention it. And I know about C99
flexible array members, but that's not the question.

I

#### Ian Collins

I seem to remember the "struct hack" is safer if the fake
dynamic array has character type. If that's right, where/why?

Why should it be?
Maybe in C99, since the struct hack is undefined in C89? Or
real life implementations, nothing to do with the standard?

That is,
typedef<char or int> T;
struct hack { Foo foo; T dynamic[1]; };

make that

struct hack { Foo foo; T dynamic[]; };

for C99.
struct hack h = malloc(sizeof *h) + sizeof(T)*n;
.... use h->dynamic[0..n-1] ...;
would be safer with T = char than with T = int.

It wouldn't compile with either. The flexible array member is irrelevant.

E

#### Eric Sosman

I seem to remember the "struct hack" is safer if the fake
dynamic array has character type. If that's right, where/why?
Maybe in C99, since the struct hack is undefined in C89? Or
real life implementations, nothing to do with the standard?

That is,
typedef<char or int> T;
struct hack { Foo foo; T dynamic[1]; };
struct hack h = malloc(sizeof *h) + sizeof(T)*n;

Garbled syntax? ITYM

struct hack *h = malloc(sizeof *h + sizeof(T)*n);
.... use h->dynamic[0..n-1] ...;

Aside: Since sizeof(*h) already includes storage for one
T element, you could use h->dynamic[0..n] (or use n-1 in the
malloc).
would be safer with T = char than with T = int.

The C FAQ does not mention it. And I know about C99
flexible array members, but that's not the question.

I can't see any reason to think a trailing char[] is any
more or less risky than a trailing T[]. Both will (almost
always) work, and neither is guaranteed to work.

Perhaps the relative riskiness involved a slightly
different situation, something like

typedef<char or whatever> T;
struct hack { int this; double that; }; // no T[]
h = malloc(sizeof *h + sizeof(T)*n);

This form certainly *is* safer with char T, because you don't
have alignment issues with the payload. (In fact, this form
is perfectly well-defined if the alignment issues are avoided
or dealt with -- but dealing with them is clumsy, hence there's
a temptation not to do so and incur the risk.)

J

#### James Kuyper

I seem to remember the "struct hack" is safer if the fake
dynamic array has character type. If that's right, where/why?
Maybe in C99, since the struct hack is undefined in C89? Or

The struct hack is no better defined in C99 than in C89. The struct hack
has undefined behavior under both versions of the standard, because it
addresses elements of an array beyond it's declared length. It worked
fine on most, and probably all, c90 compilers, but it was never required
to work. With C99, flexible array members have been added to the
language, so there's really no reason to rely upon the struct hack anymore.
real life implementations, nothing to do with the standard?

That is,
typedef <char or int> T;
struct hack { Foo foo; T dynamic[1]; };
struct hack h = malloc(sizeof *h) + sizeof(T)*n;

struct hack *h ...
.... use h->dynamic[0..n-1] ...;
would be safer with T = char than with T = int.

I know of no reason why that should be so.

H

#### Hallvard B Furuseth

Ian Collins said:
Why should it be?

No idea, so I asked here. It's just something I remember, but I
can't remeber from where. Maybe from long ago, since the hack
was shot down by stages.
Maybe in C99, since the struct hack is undefined in C89? Or
real life implementations, nothing to do with the standard?

That is,
typedef<char or int> T;
struct hack { Foo foo; T dynamic[1]; };

make that
struct hack { Foo foo; T dynamic[]; };
for C99.

Nope, not my question.
struct hack h = malloc(sizeof *h) + sizeof(T)*n;
.... use h->dynamic[0..n-1] ...;
would be safer with T = char than with T = int.

It wouldn't compile with either. The flexible array member is irrelevant.

Yes, should be malloc(sizeof *h + sizeof(T)*n) like Eric said.

K

#### Keith Thompson

Hallvard B Furuseth said:
I seem to remember the "struct hack" is safer if the fake
dynamic array has character type. If that's right, where/why?
Maybe in C99, since the struct hack is undefined in C89? Or
real life implementations, nothing to do with the standard?

I've never heard of that, and I have no reason to believe it.
It's probably either somebody's bad guess, or something that isn't
actually the struct hack, as Eric Sosman speculates.

E

#### Edward A. Falk

make that

struct hack { Foo foo; T dynamic[]; };

for C99.

What's the market penetration for C99? Is it 100%?

T dynamic[1]

Compiles with 100% of compilers.

(Yeah, I'm not much of an early adopter. For a reason.)