Carnegie Mellon MachineLevel Programming Advanced Datatypes Arrays Structs

  • Slides: 44
Download presentation
Carnegie Mellon Machine-Level Programming : Advanced Datatypes: Arrays, Structs, and Unions cs 154 Introduction

Carnegie Mellon Machine-Level Programming : Advanced Datatypes: Arrays, Structs, and Unions cs 154 Introduction to Computer Systems Junchen Jiang cs 154 ‹#›

Carnegie Mellon Back to Data � Integers ▪ Unsigned and signed (two’s complement), of

Carnegie Mellon Back to Data � Integers ▪ Unsigned and signed (two’s complement), of various sizes � What if you need some grouping of multiple values? � Arrays ▪ Collection of values, all of same type, indexed by one or more indices ▪ E. g. , A[i] (1 D array), A[i][j] (2 D array, or matrix) � Structs and unions ▪ Collections of differently typed values cs 154

Carnegie Mellon Accessing lower register bits � Lower 4 bytes of 64 -bit registers

Carnegie Mellon Accessing lower register bits � Lower 4 bytes of 64 -bit registers have names too. (textbook p 179) ▪ %eax is the lower 4 bytes of %rax ▪ %ebx is the lower 4 bytes of %rbx ▪ … � cs 154 movl, addl, subl, … access the lower 4 bytes of the source and destination (textbook p 183) ▪ E. g. , “movl %eax, %ebx” moves the 4 bytes from %eax to %ebx ▪ E. g. , “movl (%rax), %ebx” moves the 4 bytes at memory address %rax to %ebx.

Carnegie Mellon Today � Arrays ▪ Single-dimensional arrays ▪ Multi-dimensional arrays � Structs �

Carnegie Mellon Today � Arrays ▪ Single-dimensional arrays ▪ Multi-dimensional arrays � Structs � Unions cs 154

Carnegie Mellon Array Allocation Basic principle T A[L]; e. g. , int val[5] ▪

Carnegie Mellon Array Allocation Basic principle T A[L]; e. g. , int val[5] ▪ Array of data type T and length L ▪ Contiguously allocated region of L * sizeof(T) bytes ▪ Identifier A can be used as a pointer to array element 0: Type T* char string[12]; x x + 12 int val[5]; x x+4 x+8 x + 12 x + 16 x + 20 double a[3]; x x+8 x + 16 IA 32 char *p[3]; x cs 154 x x+4 x+8 x + 24 x + 12 x 86 -64 x + 16 x + 24

Carnegie Mellon Array Example #define ZLEN 5 typedef int zip_dig[ZLEN]; zip_dig uch = {

Carnegie Mellon Array Example #define ZLEN 5 typedef int zip_dig[ZLEN]; zip_dig uch = { 6, 0, 6, 3, 7 }; zip_dig cmu = { 1, 5, 2, 1, 3 }; zip_dig mit = { 0, 2, 1, 3, 9 }; 6 zip_dig uch; 16 20 1 zip_dig cmu; 36 56 � cs 154 6 24 5 40 0 zip_dig mit; � 0 28 2 44 2 60 3 32 1 48 1 64 7 3 52 3 68 36 56 9 72 76 Declaration “zip_dig uch” equivalent to “int uch[ZLEN]” These arrays were allocated in successive 20 byte blocks ▪ Not guaranteed to happen in general

Carnegie Mellon Array Access Example 6 zip_dig uch; 16 0 20 6 24 3

Carnegie Mellon Array Access Example 6 zip_dig uch; 16 0 20 6 24 3 28 int get_digit(zip_dig z, size_t dig) { return z[dig]; } # %rdi = z # %rsi = dig movl (%rdi, %rsi, 4), %eax cs 154 # z[dig] %eax: lower 32 bits of %rax movl automatically zeros higher 32 bits 7 32 36 ■ Register %rdi contains starting address of array ■ Register %rsi contains array index ■ Desired digit at 4*%rsi+%rdi ■ Use scaled indexed memory reference (%rdi, %rsi, 4)

Carnegie Mellon Array Loop Example void zincr(zip_dig z) { size_t i; for (i =

Carnegie Mellon Array Loop Example void zincr(zip_dig z) { size_t i; for (i = 0; i < ZLEN; i++) z[i]++; } # %rdi = z movl $0, jmp. L 3. L 4: addl $1, addq $1, . L 3: cmpq $4, jle. L 4 (condition) rep; ret cs 154 %eax ZLEN = 5 # i = 0 (init) # goto middle # loop: (%rdi, %rax, 4) # z[i]++ (loop body) %rax # i++ (update) # middle %rax # i: 4 # if <=, goto loop

Carnegie Mellon Array Loop Example void zincr(zip_dig z) { size_t i; for (i =

Carnegie Mellon Array Loop Example void zincr(zip_dig z) { size_t i; for (i = 0; i < ZLEN; i++) z[i]++; } Array starting address # %rdi = z movl $0, jmp. L 3. L 4: addl $1, addq $1, . L 3: cmpq $4, jle. L 4 (condition) rep; ret cs 154 ZLEN = 5 Index (i) %eax # i = 0 (init) # goto middle # loop: (%rdi, %rax, 4) # z[i]++ (loop body) %rax # i++ (update) # middle %rax # i: 4 # if <=, goto loop

Carnegie Mellon Pointer Arithmetic � Consider this code snippet int *p = 0 x

Carnegie Mellon Pointer Arithmetic � Consider this code snippet int *p = 0 x 1000; p++; ▪ What is the value of p? 1004 In general, given p which is a pointer to data of type T and has value xp, the expression p + i has value xp+L*i, where L is size of data type T � cs 154

Carnegie Mellon Pointers and Arrays 6 int val[5]; x � Reference val[4] val+1 &val[2]

Carnegie Mellon Pointers and Arrays 6 int val[5]; x � Reference val[4] val+1 &val[2] val[5] *(val+1) val + i cs 154 0 x+4 6 x+8 Type Value int int 7 x x+4 x+8 ? ? 0 x+4 i * * 3 x + 12 7 x + 16 x + 20

Carnegie Mellon Today � Arrays ▪ Single-dimensional arrays ▪ Multi-dimensional arrays � Structs �

Carnegie Mellon Today � Arrays ▪ Single-dimensional arrays ▪ Multi-dimensional arrays � Structs � Unions cs 154

Carnegie Mellon Multidimensional (Nested) Arrays � � cs 154 Declaration T A[R][C]; ▪ 2

Carnegie Mellon Multidimensional (Nested) Arrays � � cs 154 Declaration T A[R][C]; ▪ 2 D array of data type T ▪ R rows, C columns ▪ Type T element requires K bytes Array Size ▪ R * C * K bytes A[0][0] • • • A[0][C-1] • • • A[R-1][0] • • • A[R-1][C-1]

Carnegie Mellon Multidimensional (Nested) Arrays � � � Declaration T A[R][C]; ▪ 2 D

Carnegie Mellon Multidimensional (Nested) Arrays � � � Declaration T A[R][C]; ▪ 2 D array of data type T ▪ R rows, C columns ▪ Type T element requires K bytes Array Size ▪ R * C * K bytes Arrangement ▪ Row-Major Ordering A[0][0] • • • A[0][C-1] • • • A[R-1][0] • • • A[R-1][C-1] int A[R][C]; A [0] cs 154 A A • • • [0] [1] [C-1] [0] A • • • [1] [C-1] 4*R*C Bytes • • • A A [R-1] • • • [R-1] [0] [C-1]

Carnegie Mellon Nested Array Example #define PCOUNT 3 zip_dig univ[PCOUNT] = {{6, 0, 6,

Carnegie Mellon Nested Array Example #define PCOUNT 3 zip_dig univ[PCOUNT] = {{6, 0, 6, 3, 7 }, {1, 5, 2, 1, 3 }, {0, 2, 1, 3, 6 }}; zip_dig univ[3]; 6 0 6 3 7 1 5 2 1 3 0 2 1 3 6 76 � � cs 154 96 116 136 “zip_dig univ[3]” equivalent to “int univ[3][5]” (zip_dig was defined on page 6) ▪ Variable univ: array of 3 elements, allocated contiguously ▪ Each element is an array of 5 int’s, allocated contiguously “Row-Major” ordering of all elements in memory

Carnegie Mellon Nested Array Row Access � Row Vectors ▪ A[i] is array of

Carnegie Mellon Nested Array Row Access � Row Vectors ▪ A[i] is array of C elements ▪ Each element of type T requires K bytes ▪ Starting address A + i * (C * K) int A[R][C]; A[0] A cs 154 • • • A[i] A [0] [C-1] • • • A [i] [0] • • • A+(i*C*4) A[R-1] A [i] [C-1] • • • A [R-1] [0] • • • A [R-1] [C-1] A+((R-1)*C*4)

Carnegie Mellon Nested Array Row Access Code 6 0 6 3 7 1 5

Carnegie Mellon Nested Array Row Access Code 6 0 6 3 7 1 5 2 1 3 0 2 1 3 6 univ int *get_univ_zip(size_t index) { return univ[index]; } # %rdi = index, %rdx = univ leaq (%rdi, 4), %rax # 5 * index leaq %rdx(, %rax, 4), %rax # univ + (20 * index) � � cs 154 Row Vector ▪ univ[index] is array of 5 int’s ▪ Starting address univ+20*index Machine Code ▪ Computes and returns address ▪ Compute as univ + 4*(index+4*index)

Carnegie Mellon Nested Array Element Access � Array Elements ▪ A[i][j] is element of

Carnegie Mellon Nested Array Element Access � Array Elements ▪ A[i][j] is element of type T, which requires K bytes ▪ Address A + i * (C * K) + j * K = A + (i * C + j)* K int A[R][C]; A[0] A • • • A[i] A [0] [C-1] • • • • A+(i*C*4) A [i] [j] A[R-1] • • • • A [R-1] [0] • • • A [R-1] [C-1] A+((R-1)*C*4) A+(i*C*4)+(j*4)=A+(i*C+j)*4 cs 154 Total # of elements to move from A

Carnegie Mellon Nested Array Element Access Code 6 0 6 3 7 1 5

Carnegie Mellon Nested Array Element Access Code 6 0 6 3 7 1 5 2 1 3 0 2 1 3 6 univ int get_univ_digit(size_t index, size_t digit) { return univ[index][dig]; } # %rdi = index, %rsi = digit, leaq (%rdi, 4), %rax # addq %rax, %rsi # movl %rdx(, %rsi, 4), %eax # � cs 154 %rdx = univ 5*index+digit Mem[univ + 4*(5*index+digit)] Array Elements ▪ univ[index][digit] is int ▪ Address: univ + 4*(5*index + digit) = univ + 4*(index+4*index + digit)

Carnegie Mellon Nested Array Element Access Code 6 0 6 3 7 1 5

Carnegie Mellon Nested Array Element Access Code 6 0 6 3 7 1 5 2 1 3 0 2 1 3 6 univ int get_univ_digit(size_t index, size_t digit) { return univ[index][dig]; } # %rdi = index, %rsi = digit, leaq (%rdi, 4), %rax # addq %rax, %rsi # movl %rdx(, %rsi, 4), %eax # � cs 154 %rdx = univ 5*index+digit Mem[univ + 4*(5*index+digit)] Array Elements ▪ univ[index][digit] is int ▪ Address: univ + 4*(5*index + digit) = univ + 4*(index+4*index + digit)

Carnegie Mellon Nested Array Element Access Code 6 0 6 3 7 1 5

Carnegie Mellon Nested Array Element Access Code 6 0 6 3 7 1 5 2 1 3 0 2 1 3 6 univ int get_univ_digit(size_t index, size_t digit) { return univ[index][dig]; } # %rdi = index, %rsi = digit, leaq (%rdi, 4), %rax # addq %rax, %rsi # movl %rdx(, %rsi, 4), %eax # � cs 154 %rdx = univ 5*index+digit Mem[univ + 4*(5*index+digit)] Array Elements ▪ univ[index][digit] is int ▪ Address: univ + 4*(5*index + digit) = univ + 4*(index+4*index + digit)

Carnegie Mellon Nested Array Element Access Code 6 0 6 3 7 1 5

Carnegie Mellon Nested Array Element Access Code 6 0 6 3 7 1 5 2 1 3 0 2 1 3 6 univ int get_univ_digit(size_t index, size_t digit) { return univ[index][dig]; } # %rdi = index, %rsi = digit, leaq (%rdi, 4), %rax # addq %rax, %rsi # movl %rdx(, %rsi, 4), %eax # � cs 154 %rdx = univ 5*index+digit Mem[univ + 4*(5*index+digit)] Array Elements ▪ univ[index][digit] is int ▪ Address: univ + 4*(5*index + digit) = univ + 4*(index+4*index + digit)

Carnegie Mellon Multi-Level Array Example zip_dig cmu = { 1, 5, 2, 1, 3

Carnegie Mellon Multi-Level Array Example zip_dig cmu = { 1, 5, 2, 1, 3 }; zip_dig uch = { 6, 0, 6, 3, 7 }; zip_dig mit = { 0, 2, 1, 3, 6 }; � � #define UCOUNT 3 int *univ[UCOUNT] = {uch, cmu, mit}; cmu univ 160 36 168 16 176 56 uch 1 16 6 2 24 0 40 0 56 cs 154 5 20 mit 36 � 1 28 6 44 2 60 Variable univ denotes array of 3 elements Each element is a pointer ▪ 8 bytes Each pointer points to array of int’s 32 3 48 1 64 3 7 52 3 68 36 56 6 72 76

Carnegie Mellon Element Access in Multi-Level Array int get_univ_digit (size_t index, size_t digit) {

Carnegie Mellon Element Access in Multi-Level Array int get_univ_digit (size_t index, size_t digit) { return univ[index][digit]; } # %rdi = index, %rsi = digit, %rdx = univ salq $2, %rsi # 4*digit addq %rdx(, %rdi, 8), %rsi # p = univ[index] + 4*digit movl (%rsi), %eax # return *p ret Starting address of array at index � cs 154 Computation ▪ Element access Mem[univ+8*index]+4*digit] ▪ Must do two memory reads ▪ First get pointer to row array ▪ Then access element within array

Carnegie Mellon Array Element Accesses Nested array Multi-level array #define PCOUNT 3 zip_dig univ[PCOUNT]

Carnegie Mellon Array Element Accesses Nested array Multi-level array #define PCOUNT 3 zip_dig univ[PCOUNT] = {{6, 0, 6, 3, 7 }, {1, 5, 2, 1, 3 }, {0, 2, 1, 3, 6 }}; #define UCOUNT 3 int *univ[UCOUNT] = {uch, cmu, mit}; zip_dig cmu = { 1, 5, 2, 1, 3 }; zip_dig uch = { 6, 0, 6, 3, 7 }; zip_dig mit = { 0, 2, 1, 3, 6 }; int get_univ_digit (size_t index, size_t digit) { return univ[index][digit]; } Accesses look similar in C, but address computations very different: Mem[univ+20*index+4*digit] cs 154 Mem[univ+8*index]+4*digit] ‹#›

Carnegie Mellon Today � Arrays � Structs � Unions cs 154

Carnegie Mellon Today � Arrays � Structs � Unions cs 154

Carnegie Mellon Structure Representation r struct rec { int a[4]; size_t i; struct rec

Carnegie Mellon Structure Representation r struct rec { int a[4]; size_t i; struct rec *next; }; � � � cs 154 a 0 i 16 next 24 32 size_t is unsigned integer in C (8 bytes on 64 -bit machines) Structure represented as block of memory ▪ Big enough to hold all of the fields Fields ordered according to declaration ▪ Even if another ordering could yield a more compact representation Compiler determines overall size + positions of fields ▪ Machine-level program has no understanding of the structures in the source code

Carnegie Mellon Generating Pointer to Structure Member struct rec { int a[4]; size_t i;

Carnegie Mellon Generating Pointer to Structure Member struct rec { int a[4]; size_t i; struct rec *next; }; � Generating Pointer to Array Element ▪ Offset of each structure member determined at compile time ▪ Compute as r + 4*index cs 154 r a 0 i 16 next 24 32 int *get_ap (struct rec *r, size_t index) { return r->a[index]; } # r in %rdi, index in %rsi leaq (%rdi, %rsi, 4), %rax ret

Carnegie Mellon Example: Following Linked List struct rec { int a[4]; size_t i; struct

Carnegie Mellon Example: Following Linked List struct rec { int a[4]; size_t i; struct rec *next; }; void set_val (struct rec *r, size_t val) { do { int i = r->i; r->a[i] = val; r = r->next; } while (r); } cs 154 r r+4*i a 0 . L 11: movslq movl movq testq jne i 16 next 24 32 # 16(%rdi), %rax # %esi, (%rdi, %rax, 4) # 24(%rdi), %rdi # %rdi, %rdi #. L 11 # loop: i = M[r+16] M[r+4*i] = val r = M[r+24] Test r if !=0 goto loop Register Value %rdi r %rsi val

Carnegie Mellon Example: Following Linked List struct rec { int a[4]; size_t i; struct

Carnegie Mellon Example: Following Linked List struct rec { int a[4]; size_t i; struct rec *next; }; void set_val (struct rec *r, size_t val) { do { int i = r->i; r->a[i] = val; r = r->next; } while (r); } cs 154 r r+4*i a 0 . L 11: movslq movl movq testq jne i 16 next 24 32 # 16(%rdi), %rax # %esi, (%rdi, %rax, 4) # 24(%rdi), %rdi # %rdi, %rdi #. L 11 # loop: i = M[r+16] M[r+4*i] = val r = M[r+24] Test r if !=0 goto loop Register Value %rdi r %rsi val

Carnegie Mellon Example: Following Linked List struct rec { int a[4]; size_t i; struct

Carnegie Mellon Example: Following Linked List struct rec { int a[4]; size_t i; struct rec *next; }; void set_val (struct rec *r, size_t val) { do { int i = r->i; r->a[i] = val; r = r->next; } while (r); } r r+4*i a i 16 0 . L 11: movslq movl movq testq jne # 16(%rdi), %rax # %esi, (%rdi, %rax, 4) # 24(%rdi), %rdi # %rdi, %rdi #. L 11 # movslq sign extends 4 bytes to an 8 -byte destination (textbook 185) cs 154 next 24 32 loop: i = M[r+16] M[r+4*i] = val r = M[r+24] Test r if !=0 goto loop Register Value %rdi r %rsi val

Carnegie Mellon Example: Following Linked List struct rec { int a[4]; size_t i; struct

Carnegie Mellon Example: Following Linked List struct rec { int a[4]; size_t i; struct rec *next; }; void set_val (struct rec *r, size_t val) { do { int i = r->i; r->a[i] = val; r = r->next; } while (r); } cs 154 r r+4*i a 0 . L 11: movslq movl movq testq jne i 16 next 24 32 # 16(%rdi), %rax # %esi, (%rdi, %rax, 4) # 24(%rdi), %rdi # %rdi, %rdi #. L 11 # loop: i = M[r+16] M[r+4*i] = val r = M[r+24] Test r if !=0 goto loop Register Value %rdi r %rsi val

Carnegie Mellon Example: Following Linked List struct rec { int a[4]; size_t i; struct

Carnegie Mellon Example: Following Linked List struct rec { int a[4]; size_t i; struct rec *next; }; void set_val (struct rec *r, size_t val) { do { int i = r->i; r->a[i] = val; r = r->next; } while (r); } cs 154 r r+4*i a 0 . L 11: movslq movl movq testq jne i 16 next 24 32 # 16(%rdi), %rax # %esi, (%rdi, %rax, 4) # 24(%rdi), %rdi # %rdi, %rdi #. L 11 # loop: i = M[r+16] M[r+4*i] = val r = M[r+24] Test r if !=0 goto loop Register Value %rdi r %rsi val

Carnegie Mellon Structures & Alignment � Unaligned Data c i[0] p p+1 � cs

Carnegie Mellon Structures & Alignment � Unaligned Data c i[0] p p+1 � cs 154 i[1] p+5 v p+9 p+17 struct S 1 { char c; int i[2]; double v; } *p; Aligned Data ▪ Primitive data type requires K bytes Address must be multiple of K ▪ Structure address must be multiple of the largest alignment of any element

Carnegie Mellon Structures & Alignment � Unaligned Data c i[0] p p+1 � i[1]

Carnegie Mellon Structures & Alignment � Unaligned Data c i[0] p p+1 � i[1] p+5 p+9 p+17 Aligned Data ▪ Primitive data type requires K bytes Address must be multiple of K ▪ Structure address must be multiple of the largest alignment of any element c p+0 3 bytes i[0] p+4 Multiple of 4 cs 154 v struct S 1 { char c; int i[2]; double v; } *p; i[1] p+8 Multiple of 4 v 4 bytes p+16 Multiple of 8 p+24

Carnegie Mellon Structures & Alignment � Unaligned Data c i[0] p p+1 � i[1]

Carnegie Mellon Structures & Alignment � Unaligned Data c i[0] p p+1 � i[1] p+5 v p+9 Aligned Data ▪ Primitive data type requires K bytes Address must be multiple of K ▪ Structure address must be multiple of the largest alignment of any element c p+0 3 bytes p+4 i[0] i[1] p+8 Multiple of 4 Multiple of 8 Due to double element cs 154 p+17 struct S 1 { char c; int i[2]; double v; } *p; v 4 bytes p+16 p+24 Multiple of 8

Carnegie Mellon Saving Space � Put large data types first struct S 5 {

Carnegie Mellon Saving Space � Put large data types first struct S 5 { int i; char c; char d; } *p; struct S 4 { char c; int i; char d; } *p; � Effect (K=4) c i cs 154 i 3 bytes c d 2 bytes d 3 bytes

Carnegie Mellon Arrays of Structures � � Overall structure length multiple of K Satisfy

Carnegie Mellon Arrays of Structures � � Overall structure length multiple of K Satisfy alignment requirement for every element a[0] a+0 a[1] a+24 v a+24 cs 154 struct S 2 { double v; int i[2]; char c; } a[10]; i[0] a+32 • • • a[2] a+48 i[1] a+72 c a+40 7 bytes a+48

Carnegie Mellon Specific Cases of Alignment (x 86 -64) 1 byte: char, … ▪

Carnegie Mellon Specific Cases of Alignment (x 86 -64) 1 byte: char, … ▪ no restrictions on address � 2 bytes: short, … ▪ lowest 1 bit of address must be 02 � 4 bytes: int, float, … ▪ lowest 2 bits of address must be 002 � 8 bytes: double, long, char *, … ▪ lowest 3 bits of address must be 0002 � 16 bytes: long double (GCC on Linux) ▪ lowest 4 bits of address must be 00002 � cs 154

Carnegie Mellon Today � Arrays � Structs � Unions cs 154

Carnegie Mellon Today � Arrays � Structs � Unions cs 154

Carnegie Mellon Union Allocation � � Allocate according to largest element Can only use

Carnegie Mellon Union Allocation � � Allocate according to largest element Can only use one field at a time union U 1 { char c; int i[2]; double v; } *up; c i[0] i[1] v up+0 up+4 up+8 struct S 1 { char c; int i[2]; double v; } *sp; c 3 bytes sp+0 cs 154 sp+4 i[0] i[1] sp+8 4 bytes sp+16 v sp+24

Carnegie Mellon Union Example union { unsigned char C[8]; unsigned int I[2]; } dw;

Carnegie Mellon Union Example union { unsigned char C[8]; unsigned int I[2]; } dw; cs 154 union dw arg; for (int i = 0; i < 8; i++){ arg. C[i] = i; } printf("%xn", arg. I[0]); printf("%xn", arg. I[1]); c[0] c[1] c[2] c[3] c[4] c[5] c[6] c[7] 0 x 00 0 x 01 0 x 02 0 x 03 0 x 04 0 x 05 0 x 06 0 x 07 ? ? I[0] I[1]

Carnegie Mellon Union Example union dw arg; for (int i = 0; i <

Carnegie Mellon Union Example union dw arg; for (int i = 0; i < 8; i++){ arg. C[i] = i; } printf("%xn", arg. I[0]); printf("%xn", arg. I[1]); union { unsigned char C[8]; unsigned int I[2]; } dw; c[0] c[1] c[2] c[3] c[4] c[5] c[6] c[7] 0 x 00 0 x 01 0 x 02 0 x 03 0 x 04 0 x 05 0 x 06 0 x 07 ? ? I[0] I[1] Low addr Little endian Big endian cs 154 0 x 00 LSB 0 x 00 MSB High addr 0 x 01 0 x 02 0 x 03020100 0 x 01 0 x 02 0 x 00010203 0 x 03 MSB 0 x 03 LSB 0 x 04 0 x 05 0 x 06 0 x 07060504 0 x 05 0 x 06 0 x 04050607 0 x 07

Carnegie Mellon Summary � Arrays in C ▪ ▪ ▪ � Contiguous allocation of

Carnegie Mellon Summary � Arrays in C ▪ ▪ ▪ � Contiguous allocation of memory Aligned to satisfy every element’s alignment requirement Pointer to first element No bounds checking Nested, multi-level Structures ▪ Allocate bytes in order declared ▪ Alignment � Unions ▪ Overlay declarations ▪ Way to circumvent type system cs 154