1 / 43

Bit-field Structures

Special syntax packs structure values more tightly Similar to bit vectors, but arguably easier to read Nonetheless, bit vectors are more commonly used. Padded to be an integral number of words Placement is compiler-specific. f1. f2. f3. 1. 1. 0. 1. 1. 0. …. …. Bit-field Structures.

btalbert
Download Presentation

Bit-field Structures

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. Special syntax packs structure values more tightly Similar to bit vectors, but arguably easier to read Nonetheless, bit vectors are more commonly used. Padded to be an integral number of words Placement is compiler-specific. f1 f2 f3 1 1 0 1 1 0 … … Bit-field Structures struct Flags { int f1:3; unsigned int f2:1; unsigned int f3:2; } my_flags; my_flags.f1 = -2; my_flags.f2 = 1; my_flags.f3 = 2; Structures and Unions

  2. Choices: An element is an int ior a char c sizeof(union …) = maximum of sizeof(field) padding c EF BE AD DE i Unions union AnElt { int i; char c; } elt1, elt2; elt1.i = 4; elt2.c = ’a’; elt2.i = 0xDEADBEEF; Structures and Unions

  3. ? How should your program keep track whether elt1, elt2 hold an int or a char? ? Unions • A union value doesn’t “know” which case it contains union AnElt { int i; char c; } elt1, elt2; elt1.i = 4; elt2.c = ’a’; elt2.i = 0xDEADBEEF; if (elt1 currently has a char) … Basic answer: Another variable holds that info Structures and Unions

  4. Enum must be external to struct, so constants are globally visible. Struct field must be named. Tagged Unions • Tag every value with its case • I.e., pair the type info together with the union • Implicit in Java, Scheme, ML, … enum Union_Tag { IS_INT, IS_CHAR }; struct TaggedUnion { enum Union_Tag tag; union { int i; char c; } data; }; Structures and Unions

  5. Memory Allocation Alan L. Cox alc@rice.edu

  6. Objectives • Be able to recognize the differences between static and dynamic memory allocation • Be able to use malloc() and free() to manage dynamic memory in your programs • Be able to analyze programs for memory management related bugs Memory Allocation

  7. Big Picture • C gives you access to underlying data representations & layout • Needed for systems programming • Dangerous for application programming • Necessary to understand • Memory is a finite sequence of fixed-size storage cells • Most machines view storage cells as bytes • “byte-addresses” • Individual bits are not addressable • May also view storage cells as words Memory Allocation

  8. Unused User Stack Shared Libraries Heap Read/Write Data Read-only Code and Data Unused A Running Program’s Memory 0x7FFFFFFFFFFF Created at runtime 47 bits of address space Shared among processes Created at runtime Loaded from the executable 0x000000000000 Memory Allocation

  9. Allocation • For all data, memory must be allocated • Allocated = memory space reserved • Two questions: • When do we know the size to allocate? • When do we allocate? • Two possible answers for each: • Compile-time (static) • Run-time (dynamic) Memory Allocation

  10. How much memory to allocate? • Sometimes obvious: • Sometimes not: • How will these be used??? • Will they point to already allocated memory (what we’ve seen so far)? • Will new memory need to be allocated (we haven’t seen this yet)? One byte char c; int array[10]; 10 * sizeof(int) (= 40 on CLEAR) Is this going to point to one character or a string? char *c; int *array; How big will this array be? Memory Allocation

  11. malloc() Won’t continually remind you of this • Allocate memory dynamically • Pass a size (number of bytes to allocate) • Finds unused memory that is large enough to hold the specified number of bytes and reserves it • Returns a void * that points to the allocated memory • No typecast is needed for pointer assignment • Essentially equivalent to new in Java and C++ #include <stdlib.h> int *array = malloc(num_items * sizeof(int)); Memory Allocation

  12. Using malloc() Statically allocates space for 2 pointers int *i; int *array; i = malloc(sizeof(int)); array = malloc(num_items * sizeof(int)); *i = 3; array[3] = 5; • i and array are interchangeable • Arrays  pointers to the initial (0th) array element • i could point to an array, as well • May change over the course of the program • Allocated memory is not initialized! • calloc zeroes allocated memory (otherwise, same as malloc; details to come in lab) Dynamically allocates space for data Memory Allocation

  13. Using malloc() • Always check the return value of system calls like malloc() for errors • For brevity, won’t in class • Lab examples will • Textbook uses capitalization convention • Capitalized version of functions are wrappers that check for errors and exit if they occur (i.e. Malloc) • May not be appropriate to always exit on a malloc error, though, as you may be able to recover memory int *a = malloc(num_items * sizeof(int)); if (a == NULL) { fprintf(stderr,“Out of memory.\n”); exit(1); } Terminate now! And, indicate error. Memory Allocation

  14. Static time Typically global variables: Only one copy ever exists, so can allocate at compile-time Dynamic time Typically local variables: One copy exists for each call – may be unbounded # of calls, so can’t allocate at compile-time When to Allocate? int f(…) { int value; … } int main(void) { … } int value; int main(void) { … } Memory Allocation

  15. One copy exists for all calls – allocated at compile-time When to Allocate? • Static time • Some local variables: int f(…) { static int value; … } int main(void) { … } Confusingly, local static has nothing to do with global static! Memory Allocation

  16. Allocation in Process Memory 0x7FFFFFFFFFFF Stack Static size, dynamic allocation Local variables Shared Libraries Programmer controlled (variable-sized objects) Heap Dynamic size, dynamic allocation Read/Write Data Static size, static allocation Global variables (and static local variables) Read-only Code and Data 0x000000000000 Memory Allocation

  17. Deallocation • Space allocated via declaration (entering scope) is deallocated when exiting scope • Can’t refer to y or array outside of f(), so their space is deallocated upon return … f(void) { int y; int array[10]; … } Memory Allocation

  18. Deallocation • malloc() allocates memory explicitly • Must also deallocate it explicitly (using free())! • Not automatically deallocated (garbage collected) as in Python and Java • Forgetting to deallocate leads to memory leaks & running out of memory • Must not use a freed pointer unless reassigned or reallocated int *a = malloc(num_items * sizeof(int)); … free(a); … a = malloc(2 * num_items * sizeof(int)); Memory Allocation

  19. Deallocation • Space allocated by malloc() is freed when the program terminates • If data structure is used until program termination, don’t need to free • Entire process’ memory is deallocated Memory Allocation

  20. Back to create_date Date * create_date3(int month, int day, int year) { Date *d; d->month = month; d->day = day; d->year = year; return (d); } Date * create_date3(int month, int day, int year) { Date *d; d = malloc(sizeof(Date)); d->month = month; d->day = day; d->year = year; return (d); } Memory Allocation

  21. Potential problem: memory allocation is performed in this function (may not know its implementation) Memory is still allocated for “today”! Will never be deallocated (calling function doesn’t even know about it) Pitfall void foo(void) { Date *today; today = create_date3(1, 24, 2017); /* use “today” */ ... return; } Memory Allocation

  22. Possible Solutions void foo(void) { Date *today; today = create_date3(…); /* use “today” */ ... free(today); return; } void foo(void) { Date *today; today = create_date3(…); /* use “today” */ ... destroy_date(today); return; } Explicitly deallocate memory – specification of create_date3 must tell you to do this Complete the abstraction – “create” has a corresponding “destroy” Memory Allocation

  23. Common Memory Management Mistakes Memory Allocation

  24. What’s Wrong With This Code? int *f(…) { int i; … return (&i); } int *make_array(…) { int array[10]; … return (array); } • Consider j = *f() • Leads to referencing deallocated memory • Never return a pointer to a local variable! • Behavior depends on allocation pattern • Space not reallocated (unlikely)  works • Space reallocated  very unpredictable Memory Allocation

  25. One Solution • Allocate with malloc(), and return the pointer • Upon return, space for local pointer variable is deallocated • But the malloc-ed space isn’t deallocated until it is free-d • Potential memory leak if caller is not careful, as with create_date3… int *f(…) { int *i_ptr = malloc(sizeof(int)); … return (i_ptr); } int *make_array(…) { int *array = malloc(10 * sizeof(int)); … return (array); } Memory Allocation

  26. Initialization loop for y[] i=0 j=0 What’s Wrong With This Code? • malloc-ed & declared space is not initialized! • i, j, y[i] initially contain unknown data – garbage • Often has zero value, leading to seemingly correct results /* return y = Ax */ int *matvec(int **A, int *x) { int *y = malloc(N * sizeof(int)); int i, j; for (; i<N; i+=1) for (; j<N; j+=1) y[i] += A[i][j] * x[j]; return (y); } Memory Allocation

  27. What’s Wrong With This Code? • Allocates wrong amount of memory • Leads to writing unallocated memory char **p; int i; /* Allocate space for M*N matrix */ p = malloc(M * sizeof(char)); for (i = 0; i < M; i++) p[i] = malloc(N * sizeof(char)); char * Memory Allocation

  28. Explanation Heap region in memory (each rectangle represents one byte) Assume M = N = 2, a memory address is 64 bit or 8 byte for (i = 0; i < M; i++) p[i] = malloc(N * sizeof(char)); ` p[0] p = malloc(M * sizeof(char)); Memory Allocation

  29. Corrected code Heap region in memory (each rectangle represents one byte) Assume M = N = 2, a memory address is 64 bit or 8 byte for (i = 0; i < M; i++) p[i] = malloc(N * sizeof(char)); ` p[1] p[0] p = malloc(M * sizeof(char *)); Memory Allocation

  30. < What’s Wrong With This Code? • Off-by-1 error • Uses interval 0…M instead of 0…M-1 • Leads to writing unallocated memory • Be careful with loop bounds! char **p; int i; /* Allocate space for M*N matrix */ p = malloc(M * sizeof(char *)); for (i=0; i<=M; i+=1) p[i] = malloc(N * sizeof(char)); Memory Allocation

  31. Using const • const int * size • Pointer to a constant integer • Cannot write to *size • int * const size • Constant pointer to an integer • Cannot modify the pointer (size) • Can write to *size char * xyz(char * to, const char * from) { char *save = to; for (; (*to = *from); ++from, ++to); return(save); } Memory Allocation

  32. What’s Wrong With This Code? • t[] doesn’t have space for string terminator • Leads to writing unallocated memory • One way to avoid: char * strcpy(char * to, const char * from) { char *save = to; for (; (*to = *from); ++from, ++to); return(save); } char *s = “1234567”; … char t[7]; strcpy(t, s); char *s = “1234567”; … char *t = malloc((strlen(s) + 1) * sizeof(char)); strcpy(t, s); Memory Allocation

  33. p += 1; What’s Wrong With This Code? • Misused pointer arithmetic • Search skips some data, can read unallocated memory, and might not ever see value • Should never add sizeof() to a pointer • Could consider rewriting this function & its uses to use array notation instead /* Search memory for a value. */ /* Assume value is present. */ int *search(int *p, int value) { while (*p > 0 && *p != value) p += sizeof(int); return (p); } Memory Allocation

  34. What’s Wrong With This Code? • Premature free() • Reads and writes deallocated memory • Behavior depends on allocation pattern • Space not reallocated  works • Space reallocated  very unpredictable x = malloc(N * sizeof(int)); … free(x); … y = malloc(M * sizeof(int)); for (i = 0; i < M; i++) { y[i] = x[i]; x[i] += 1; } Memory Allocation

  35. free(x); What’s Wrong With This Code? • Memory leak – doesn’t free malloc-ed space • Data still allocated, but inaccessible, since can’t refer to x • Slows future memory performance void foo(void) { int *x = malloc(N * sizeof(int)); … return; } Memory Allocation

  36. What’s Wrong With This Code? struct ACons { int first; struct ACons *rest; }; typedef struct ACons *List; List cons(int first, List rest) { List item = malloc(sizeof(struct ACons)); item->first = first; item->rest = rest; return (item); } void foo(void) { List list = cons(1, cons(2, cons(3, NULL))); … free(list); return; } A peek at one way to define lists Memory Allocation

  37. Example continued • Memory leak – frees only beginning of data structure • Remainder of data structure is still allocated, but inaccessible • Need to write deallocation (destructor) routines for each data structure Memory Allocation

  38. Putting it together… • string • pointer • struct • malloc() • simple I/O • simple string operations Memory Allocation

  39. What does action1() do? struct thing { char *stuff; struct thing *another_thing; }; void action1(struct thing **y, const char *stuff) { struct thing *x = malloc(sizeof(struct thing)); /* Alternatively, x->stuff = strdup(stuff); */ x->stuff = malloc(strlen(stuff) + 1); strcpy(x->stuff, stuff); x->another_thing = *y; *y = x; } int main(void) { struct thing *y = NULL; action1(&y, "Cox"); #include <stdio.h> #include <stdlib.h> #include <string.h> action1() inserts a new node storing the specified string into the linked list Memory Allocation

  40. What does action2() do? struct thing { char *stuff; struct thing *another_thing; }; void action2(struct thing **y) { struct thing *x; while ((x = *y) != NULL) { printf("%s ", x->stuff); y = &x->another_thing; } putchar('\n'); } int main(void) { struct thing *y = NULL; ... action2(&y); action2() prints the strings stored in the linked list nodes sequentially Memory Allocation

  41. What does action3() do? struct thing { char *stuff; struct thing *another_thing; }; int action3(struct thing **y, const char *stuff) { struct thing *x; while ((x = *y) != NULL) { if (strcmp(x->stuff, stuff) == 0) return (1); else y = &x->another_thing; } return (0); } int main(void) { struct thing *y = NULL; ... action3(&y, "Cox"); action3() finds out whether a string is stored in the linked list Memory Allocation

  42. What does action4() do? struct thing { char *stuff; struct thing *another_thing; }; void action4(struct thing **y, const char *stuff) { struct thing *x; while ((x = *y) != NULL) { if (strcmp(x->stuff, stuff) == 0) { *y = x->another_thing; free(x->stuff); free(x); return; } else y = &x->another_thing; } } int main(void) { struct thing *y = NULL; ... action4(&y, "Cox"); action4() deletes the first list node that stores the specified string style compromised to save space Memory Allocation

  43. Next Time • Lab: Debugging • Assembly Memory Allocation

More Related