tags:

views:

193

answers:

4

i come from a php background and am studying this page http://cocoadevcentral.com/articles/000081.php before i step foot into some of the harder stuff in regards to objective-c

if i type something like this

typedef struct { 
int lengthInSeconds; 
int yearRecorded; 
} Song; 

and when setting a function or a variable of type Song, what does it mean? i understand that by setting a function as an int or maybe a float the output would be related to its type set. but when i do something like this

Song myvariable;
or
Song myfunction(int params) { }

what type is Song setting?

thanks

+1  A: 

Here is a wikipedia article on C's structs.

http://en.wikipedia.org/wiki/Struct_%28C_programming_language%29

Daniel A. White
i read the article on wikipedia. but dont understand its purpose, would it be similar to writing classes in php?
SarmenHB
Structs are similar to classes in that they group up several other variables (in this case, two ints) into a self-contained packet of data (see other answers by NSResponder and lpthnc). The ideologies of a C struct and a PHP class are rather different, though.
Asher Dunn
+2  A: 

Assuming that Objective C is very close to C, you do this:

Song myvariable; // creates the truct in memory
myvariable.lengthInSeconds = 10;
myvariable.yearRecorded = 2010;

I cannot say what the function does because you have not given its impl.

Here is how you fix the function to do something "useful":

Song myfunction(int params) { 
  Song ret;
  ret.lengthInseconds = params * 69;
  ret.yearRecorded = 3*5*7*9*11;
  return ret;
}

(Jut to illustrate that the function can do whatever ...

Hamish Grubijan
+2  A: 

In the first case:

Song myvariable;

You're declaring myvariable to be an instance of the struct you declared in your typedef.

In the second case:

Song myfunction(int params) { }

You're declaring a function that takes one integer, and returns a Song. Since there's no code in the curly braces, you're not actually returning anything, and the compiler would report an error in your code.

NSResponder
I would just add that the first means "Reserve enough memory space to hold a structure of type Song and call it myvariable" while the second is: "I promise that this function will return a structure of type Song".
Remo.D
+11  A: 

I think it would help you the most to know just what is going on in the compiler's head. Using your example:

typedef struct { 
int lengthInSeconds; 
int yearRecorded; 
} Song;

There are actually two things happening here. The first is that you're defining an anonymous struct:

struct { 
int lengthInSeconds; 
int yearRecorded; 
}

This anonymous struct can be used anywhere a type (e.g. int or const char*) could be used. The following example is actually valid, though nobody should ever write code like this because it's a maintenance nightmare:

struct { 
int lengthInSeconds; 
int yearRecorded; 
}* GetSongInfo(const char* songName);

This declares a function that gets the information for a song with a given name (assuming names are unique, an invalid assumption in real life) and returns a pointer to a struct with its metadata.

I referred to that as an "anonymous struct" because the named struct form looks like this:

struct Song { 
int lengthInSeconds; 
int yearRecorded; 
}

Now you can refer to that struct by name, but not in the fashion you would think coming from languages other than C! Specifically, the function above would now be declared as:

struct Song* GetSongInfo(const char* songName);

Note that the type name is struct Song and not just Song! As a matter of fact, structs have a separate namespace of their own... so there is nothing in the language to guarantee that struct Song and Song are the same thing! I have no idea if Objective C maintains this insanity, but I'd bet it does to be on the safe side.

The second thing is that you're feeding that anonymous structure to typedef. typedef simply takes one type and defines a name for it that you can use later. So you're really saying "a Song is an alias for that struct {...} I just declared."

By typedefing Song, you can instead write:

Song* GetSongInfo(const char* songName);

(Yes, I know it would be better to return const Song*, but that's beside the point.)

It may interest you to note that C has many typedefs in its standard libraries, intended to separate the particulars of a platform from the particulars of the C standard. For example, <unistd.h> defines size_t, the integer type that represents a size (and is the return type of the built-in sizeof() function), and by extension, the type you should pass to functions like malloc(). There is also the recent <stdint.h> header which defines integer types by their size in bits, e.g. uint8_t for an 8-bit unsigned integer. The line in <stdint.h> probably looks something like:

typedef unsigned char uint8_t;

Since most platforms have 8-bit characters. (I've programmed for some platforms like TI DSPs where a char was not 8-bits; usually it was 16, since the processor could not access parts of words. But let's ignore degenerate platforms for the time being.)

Finally, to explain your examples:

Song myvariable;

This declares storage for a Song structure. If it is in a function definition, that storage will be allocated on the stack and released when the function terminates. If it is outside a function definition, it will be allocated as a global. In either case, it will be uninitialized, which in C means it can contain any random values. C does not keep track of uninitialized variables or set them to "uninitialized" or whatever like PHP and Python does. C doesn't throw exceptions either.

Song myfunction(int params) { }

This defines a function that takes an integer and returns a Song structure. The return statement for the function must be given a Song. For example:

Song myfunction(int params)
{
    Song result;
    result.lengthInSeconds = GetSongLength(params); 
    result.yearRecorded = GetSongYear(params); 
    return result;
}

This function allocates space on the stack for a Song, fills in its fields by calling functions that return ints, then return copies the structure result into the space reserved for the return value, and finally the storage for result is released when the function ends. Usually, the compiler can optimize away the copy implicit in the return statement. Also, there may be another (possibly optimized) copy from the return value storage to a final destination, for example when you say:

Song foundSongInfo = myfunction(params);

By the way, returning structs on the stack is frowned upon, since compilers can usually optimize better if the return value fits in a register (i.e. is a simple type). (There are exceptions in C++ with operator overloading, but that's off-topic.) A better definition would be:

void myfunction(int params, Song* found)
{
    found->lengthInSeconds = GetSongLength(params); 
    found->yearRecorded = GetSongYear(params); 
}

This avoids all the extra copies. You call it like so:

Song foundSongInfo;
myfunction(params, &foundSongInfo);

This is one case where two lines can be faster than one.

I may have missed some things, let me know if this makes sense...

Mike DeSimone