1 / 27

CS1336, Structs, Unions and Enums

CS1336, Structs, Unions and Enums. A lecture for you while I'm gone. Outline. Review of Array vs Struct Structs and memroy Union Enumerated values. Structs vs Arrays. What's an array? A bunch of items of the same type one after another in memory.

billy
Download Presentation

CS1336, Structs, Unions and Enums

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. CS1336, Structs, Unions and Enums A lecture for you while I'm gone

  2. Outline • Review of Array vs Struct • Structs and memroy • Union • Enumerated values

  3. Structs vs Arrays • What's an array? • A bunch of items of the same type one after another in memory. • Useful for keeping up with lists of similar, related things • Each item is called an element • We get to each element using its integer index. • There's little difference between an array and a pointer to an array (but some difference)

  4. Structs vs Arrays • What's a struct • A bunch of items of (potentially) different types one after another in memory. • Useful for keeping up with related, but potentially dissimilar things • Items in a struct are called fields • We get to the fields of a struct using their names • Different syntax for a struct and a pointer to a struct: • For a struct: a.color = red; • For a pointer to a struct: a->color = red;

  5. Making Structure Instances • We use the term, instance, to talk about a value of some struct type that's been allocated in memory. • We can make an instance of MyStruct on the runtime stack with:# Goes away when the variable goes out of scope.struct MyStruct a; • We can dynamically allocate an instance of MyStruct with:# doesn't go away until we free it.struct MyStruct *a = (struct MyStruct *)malloc( sizeof( struct MyStruct ) );

  6. Structs and Binary I/O • An instance of a struct occupies a contiguous region of memory • We should be able to read an write the whole thing by writing its memory • struct MyStruct a; • fread( &a, sizeof( struct MyStruct ), 1, fp ); • fwrite( &a, sizeof( struct MyStruct ), 1, fp ); • Just like with primitive types, the file here will contain binary data reflecting what the structure looks like in memory.

  7. Structs and Binary I/O • Binary I/O of entire structs is convenient, but it has some consequences • May be non-portable between different system architectures because of byte ordering issues. • Depending on the compiler and the system architecture, a struct instance may contain unused bytes called padding • This padding wastes space in the file and, since it may depend on the compiler, it reduces portability

  8. Padding in a Struct • Most processors are more efficient if or require that you are careful about what kind memory address a value starts at. • For example, many systems expect an int to start at an even byte boundary. • It would be ok for an int to be stored at addresses 0xffe8, 0xb43c2a or 0x3ccb0 • It would not be ok for an int to be stored at address 0xff, 0xb43c2b or 0x9207 • We say some systems require a value to be aligned in memory • Alignment requirements typically only apply to primitive types that are larger than a byte (int, foat, double, long int, short, etc.)

  9. Padding in a Struct • We say a value is naturally aligned if it starts at an address that's a multiple of its size. • For example, a 4-byte int would be naturally aligned if it started at an address that's a multiple of 4 • A 2-byte short would be naturally aligned if it started on an even numbered address • A compiler may align values in a struct either because the system requires it or because it will make the code faster.

  10. Padding in a Struct • Aligning the elements of a struct may leave spaces between them • Pretend this struct will be compiled on a system that requires values larger than a byte to be even-byte aligned. struct MyStruct { char a; /* 1-byte field. */ int b; /* 4-byte field. */ char c; /* 1-byte field. */ short d; /* 2-byte field. */ } • The compiler will have to introduce a byte of padding between after each char, just to make sure the next field is properly aligned.

  11. Padding in a Struct • Even-byte padding example, continued. • The struct will end up looking like this (the pad fields aren't really there, I'm just showing where the compiler will put extra space): struct MyStruct { char a; /* 1-byte field. */ char pad; /* 1 byte of padding. */ int b; /* 4-byte field. */ char c; /* 1-byte field. */ char pad; /* 1 byte of padding. */ short d; /* 2-byte field. */ } • Because of the padding, sizeof will report 10 bytes for this struct even though we only need to store 8 bytes of data. • On a system that required ints to be naturally aligned, this struct would receive even more padding • For example, my laptop wants the b to be 4-byte aligned.

  12. Structs and Padding • We have some influence over how much padding occurs. • We could reorder fields to reduce padding. struct MyStruct { int b; /* 4-byte field. */ char a; /* 1-byte field. */ char c; /* 1-byte field. */ short d; /* 2-byte field. */ } • Here, no padding would be required on a system that expected even-byte alignment.

  13. Alternatives to Binary Struct I/O • Reading and writing whole structure instances in binary is convenient, but it may waste space because of padding and may inhibit portability • Still, lots of software systems do this kind of thing when these issues are not important • We have some alternatives • Read and write each field one after another in some human readable format • Could use printf/scanf • File would be human readable, which is nice • No extra padding will be required • Format would be very portable • However, a human readable format often requires more storage • Consider, the int 2458154370 is 10 ASCII characters, but the would require only 4 bytes if written to a binary file.

  14. Alternatives to Binary Struct I/O • We have some alternatives, continued • Read and write each field one after another in binary • Could use fread/fwrite for each field. • No extra padding will be required • Encoding of each field would typically be cheap (in storage) • We would have to consider portability issues like byte order for each field

  15. Inspecting a Struct • We can use the sizeof() operator to find out how much memory a struct instance requires • We can also do some pointer tricks to find out where each of its fields start inside the instance (the offset for each field) • Pretend MyStruct is a struct • We can take a null pointer and pretend it's a pointer to a MyStruct instance:(struct MyStruct *)NULL • We can talk about a field of this MyStruct instance starting at memory address zero:((struct MyStruct *)NULL)->myField • We can talk about the address of myField in a structure starting at memory address zero:&(((struct MyStruct *)NULL)->myField) • If we cast this to an int, we can print out the offset of myField in an instance of MyStruct(int) &((struct MyStruct *)NULL)->myField

  16. Union • We have been thinking about how something like a struct instance is organized in memory. • Now is a good time to think about union • Syntax for union is almost the same as struct:union Example { int a; char b; double c;} • However, instead of laying out its fields one after another in memory, the union organizes them one over another in memory • Every union field starts at the same offset, just the start of the structure • Memory size of the union is the size of it's largest field. • We can check using the trick we already figured out.(int) &(((union Example *)NULL)->b) == 0

  17. Why use Union • Union has a strange behavior and it's not used as much as struct • It is useful when: • You don't know you will sometimes have to store a value of one type and sometimes a value of a different type • but you won't have to store both values at the same time • You want to save memory by using the same memory to store both. • Union really just gives us multiple ways of looking at or using the same memory

  18. A Use for Union • Consider the union:union Integer { int ival; unsigned char bval[ sizeof( int ) ]; }; • Here, the int and character arrays are really different ways to get to the same memory. • This would make it easy to work with an int stored in ival either as a whole int or a byte at a time./* Put a value into our integer. */ union Integer i; i.ival = 0xffb0; /* Extract its representation a byte at a time. */ int j; for ( j = 0; j < sizeof( int ); j++ ) printf( "%d ", i.bval[ j ] ); printf( "\n" );

  19. Union inside Struct • Union is most often used inside a struct • This gives us a way to make a struct that be used to hold similar, but different things • The following struct can be used to store either an int, a float and a double or an int, a float and a short string.struct MyVariantStruct { /* First two fields are always there. */ int a; float b; /* Variant part of the struct, can contain a double or a short string. */ union VPart { double c; char d[ 10 ]; } vpart;};

  20. Union in a Struct • Syntax for this example is a little difficult • Inside the structure, we are defining a new union type called VPart. • At the end of the VPart definition, we add a new field of type VPart to the struct, the field is called vpart • We can get to the fields of a MyVariantStruct instance just like you would expect:MyVariantStruct bob;bob.a = 20;bob.b = -283.6;/* Get to the union in bob and use its double field */bob.vpart.c = 3.1415;/* Get to the union in bob and use its character array field. This will overwrite what we just stored in c. */strcpy( bob.vpart.d, "Hello!" ); • Consider, what would the size of MyVariantStruct be?

  21. Anonymous Unions • Union inside a struct is so common, we can use an abbreviated syntax for it. • We can leave out the type name and the field name for the union inside our struct.struct MyVariantStruct { /* First two fields are always there. */ int a; float b; /* This is called an anonymous union */ union { double c; char d[ 10 ]; };};

  22. Anonymous Unions • Now, we can use shorter syntax to get to the variant part of the structureMyVariantStruct bob;bob.a = 20;bob.b = -283.6;/* Write to the double field in bob's union */bob.c = 3.1415;/* Write to the character field in bob's union */strcpy( bob.d, "Hello!" );

  23. Enumerated Types • You probably saw this in CS1, but it's on my list of stuff to teach. • An enumerated type is a way to make your own type containing a specific set of values that you pick • An enumerated type is a lot like an int, and is even represented as numbers in the compiled code • Example:/* Define a new type called Color, with 7 colors as its only legal values. */enum Color { RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET };/* Show off how we can use this type. */Color favorite = GREEN;if ( favorite != RED ) printf( "You have the wrong favorite color\n" ); • Values in an enumeration are usually given in all capitals, since they are like constants • Values in an enumeration automatically promote to int

  24. Enumerated Types • Enum is represented as a number • By default, the first value in the definition (RED on the previous slide) gets represented by zero. • Subsequent values in the enumeration are represented by the next integer • So, YELLOW is represented by 2 and VIOLET is represented by 6 • You will see this number if you try to print a variable of some enum type:printf( "%d\n", favorite ); • You can assign directly from an int (requires a type cast in C++)enum Color favorite = (enum Color) 3;

  25. Fun with Enum • You can pick the numbers used to represent values in your enumerated typeenum Color { RED = 1, ORANGE = 3, VIOLET = 6, BLUE, GREEN = 0, PURPLE }; • Here, BLUE will be represented by 7 since enum values are get the value one after their predecessor. • Notice that PURPLE and RED will both be represented by 1. This will make them indistinguishable. Here, they are just two names for the same value.

  26. Uses for Enum • It's unfortunate that enumerated values print as numbers rather than their names. • Likewise, the user can't type the name of an enumerated value as program input • The way you should think of enum is as a mechanism for making your program more readable and for using a more specific type than int where possible • Using an enumerated type where you can may make it easier for someone else to understand your program • An enumerated type as a function parameter makes it easier to make sure you have called the function with a meaningful value

  27. Examples of Enum Use • Enum can be particularly appropriate for values that will govern a switch statement:enum Direction { NORTH, SOUTH, EAST, WEST };…void move( Direction d ) { switch ( d ) { case NORTH: /* Do something useful. */ break; case SOUTH: /* Do something else. */ break; ... }}

More Related