/* ** $Id: sizeof.c 789 2008-02-23 06:27:49Z phf $ ** ** Examples of using the "sizeof" operator in preparation ** for malloc(3) and free(3). We use "sizeof" to determine ** the size (in terms of "bytes of memory") of declarations. */ #include #include #include #include // Start reading at main() below, we'll get back to these // three later... :-) void ta( char s[] ) { printf( "%ld\n", sizeof(s) ); } void tp( char *s ) { printf( "%ld\n", sizeof(s) ); } void tx( char s[32] ) { printf( "%ld\n", sizeof(s) ); } int main(void) { // The use of "sizeof" looks like a function, but it is // not: Rather the C compiler itself understands sizeof, // thus the usual rules for functions don't apply. For // example, we can pass a *type* to sizeof. Note that // the sizes given in comments below are for my PowerPC // Mac laptop; your machine probably differs a little. printf( "%ld\n", sizeof(int) ); // prints 4 printf( "%ld\n", sizeof(char) ); // prints 1 puts( "----------" ); // Actually, even when it looks like we're passing values, // we're really passing the information associated by the // compiler with a certain declaration. So here are a few // variables and we'll determines those sizes next. :-) short int si; int i; long int li; long long int lli; double d; char c; bool b; printf( "%ld\n", sizeof(si) ); // prints 2 printf( "%ld\n", sizeof(i) ); // prints 4 printf( "%ld\n", sizeof(li) ); // prints 4 printf( "%ld\n", sizeof(lli) ); // prints 8 printf( "%ld\n", sizeof(d) ); // prints 8 printf( "%ld\n", sizeof(c) ); // prints 1 printf( "%ld\n", sizeof(b) ); // prints 4 puts( "----------" ); // We can also ask for the size of more complex types, // here are a few structs for example. struct { int a; int b; double d; } sa; struct { int a; char c; int b; double d; } sb; struct { int a; int b; double d; char c; } sc; struct { char c; } sd; struct { char c; int a; } se; printf( "%ld\n", sizeof(sa) ); // prints 16 printf( "%ld\n", sizeof(sb) ); // size in bytes 20 (!) printf( "%ld\n", sizeof(sc) ); // size in bytes 20 (!) printf( "%ld\n", sizeof(sd) ); // prints 1 printf( "%ld\n", sizeof(se) ); // prints 8 (!) puts( "----------" ); // Note that the first of these makes perfect sense // since we have 2 ints of 4 bytes each and a double // of size 8. In the next two, things are different: // We add a char of size 1 but the size of the struct // jumps up by 4! The reason is that the C compiler // will insert some "padding" to make sure that data // is "aligned" correctly in memory. It's complicated // but the point is: Don't expect that the sizes of // struct components add up! Finally there's a struct // that has the same exact size as its component. // Here's an example involving pointers, those must // have some size as well, right? struct node { struct node *next; char data; }; struct node *head = NULL; printf( "%ld\n", sizeof(struct node) ); // prints 8 (why? :-) printf( "%ld\n", sizeof(head) ); // prints 4 puts( "----------" ); // Now let's look at arrays for a moment, starting with // a few simple ones. int az[0]; // we'll get a warning here, luckily... int ao[1]; int at[10]; int ai[] = {20, 30, 40}; printf( "%ld\n", sizeof(az) ); // prints 0 printf( "%ld\n", sizeof(ao) ); // prints 4 printf( "%ld\n", sizeof(at) ); // prints 40 printf( "%ld\n", sizeof(ai) ); // prints 12 puts( "----------" ); // Switching to strings, we're in for a few surprises... char st[] = "Wonderful"; char *sp = "Wonderfuller"; char sx[32]; strcpy( sx, "Aha!" ); printf( "%s %ld\n", st, sizeof(st) ); // prints 10 printf( "%s %ld\n", sp, sizeof(sp) ); // prints 4 printf( "%s %ld\n", sx, sizeof(sx) ); // prints 32 puts( "----------" ); // Notice that there *is* a difference between the first // two after all. Also notice that they all "work" the // same in terms of printing. That's because almost all // "expression contexts" an array will be converted to // a pointer to the first element of the array. Also, // make sure you notice that sizeof doesn't behave in // any way like strlen(), especially not for "sx" above. // Now we get back to the functions declared before main. // Take a quick peek and look at the way the parameters // are declared: They mirror the declarations for st, sp, // and sx we just used. Be prepared for another shock: ta( "What do you expect?" ); // prints 4 tp( "Anything different here?" ); // prints 4 tx( "This is scary as well..." ); // prints 4 puts( "----------" ); // If you use any of the declarations as a parameter to // a function, they *literally* are all pointers. Quite // a ride learning C, isn't. :-) // Finally, note that sizeof works on all kinds of types, // even those defined in the standard library. So I said // that FILE is something you should simply use, but you // shouldn't care about what the *insides* of it are like. // Well, you can certainly find out one thing: how big is // the type that represents a file in your implementation // of the standard library? printf( "%ld\n", sizeof(FILE) ); // prints 88 printf( "%ld\n", sizeof(FILE*) ); // prints 4 (of course) return EXIT_SUCCESS; }