bernd said:
a simple question for the experts, I guess.
Obviously I am doing something wrong when trying to access an element
of an array declared within a structure:
#include <stdio.h>
#include <stddef.h>
main() {
const int SIZE = 2 ;
struct test {
long type ;
size_t files[SIZE] ;
} ;
struct test example ;
example.type = 100 ;
example.files[0] = 2 ;
printf("type %d - file size %lld:\n", example.type,
example.files[0] ) ;
}
The "%d" format requires an argument of type int; you're giving it an
argument of type long (example.type). It happens to "work" for you,
probably because your implementation makes int and long the same size,
but even that doesn't guarantee anything, and it will break on other
implementations.
The "%lld" format requires an argument of type long long; you're
giving it an argument of type size_t (example.files[0]).
It's not sufficient for a format to specify a type that can hold the
value of the corresponding argument, or one that's at least as big as
the argument type, or even that's the same size and signedness. You
have to match the types exactly. (There are some minor exceptions to
this, but they're best ignored; it's easier to match the type exactly
all the time than to remember the circumstances where you can fudge
things a bit.)
In C90, there's no format for size_t. C99 adds "%zu", but you might
not have a C99 implementation (if you did, it would have been required
to issue a diagnostic for your use of implicit int.)
The compiler didn't complain about the mismatch because it's not
required to. The format string is something that exists at run time;
it could have been a variable rather than a string literal. Some
compilers will do some format string checking for you, but in general
you just need to get it right yourself.
Here's how to print those values:
printf("type %ld - file size %lu:\n",
example.type,
(unsigned long)example.files[0]);
That's for C90, and it also works in C99 (as long as the value of
example.files[0] doesn't happen to exceed ULLONG_MAX). Note that the
cast is necessary to ensure that the types match exactly (this is one
of the rare cases where a cast is necesssary and appropriate).
If you're sure your code won't be used with a pre-C99 implementation,
you can do this instead:
printf("type %ld - file size %zu:\n",
example.type,
example.files[0]);
But if you happen to use the above with an implementation that doesn't
support "%zu", it's not required to tell you that it doesn't recognize
the format.
There are some other things you should fix that aren't relevant to
what you were asking about.
"main()" should be "int main(void)". The form you use can work under
some implementations, but "int main(void)" will *always* work
(assuming a hosted implementation rather than a freestanding
implementation).
SIZE is not actually a constant; it's merely a read-only object. This
means that if you use it as an array length, then it's a VLA
(variable-length array). VLAs are not allowed at all in C90, and are
not allowed as structure members even in C99. If the above compiled
without diagnostics, then either you're using a compiler that provides
some sort of extension (and you're invoking it in non-conforming
mode), or you're using a C++ compiler (<OT>in C++ SIZE *is* a
constant</OT>). You can replace your
const int SIZE = 2 ;
with
#define SIZE 2
You should add "return 0;" before the closing '}'. There are
circumstances where it's not necessary, but this is another case where
it's easier to use something that's universally valid than to keep
track of the cases where you can get away with something else. main
returns an int, so you should return an int; 0 is a safe value.
Finally, a style point. I personally dislike white space before a
semicolon. The compiler doesn't care, of course, and some programmers
will disagree with me, but I think most people write semicolons with
no preceding blank.
Here's your program as I would have written it (I've taken the liberty
of changing the output format a bit):
#include <stdio.h>
#include <stddef.h>
int main(void)
{
#define SIZE 2
struct test {
long type;
size_t files[SIZE];
};
struct test example;
example.type = 100;
example.files[0] = 2;
printf("example.type = %ld, example.files[0] = %lu\n",
example.type, (unsigned long)example.files[0]);
return 0;
}