T A[L]
T
and length L
L * sizeof(T)
bytes in memorychar string[12]
: 12 * sizeof(char)
= 12 bytesint val[5]
: 5 * sizeof(int)
= 20 bytesT*
Examples: int val[5] = {1, 5, 2, 3, 1};
Reference | Type | Value |
---|---|---|
val[4] |
int |
1 |
val |
int * |
x |
val+1 |
int * |
x+4 |
&val[2] |
int * |
x+8 |
*(val+1) |
int |
5 |
where x
is the address of the first byte of val
C code
#define ZLEN 5
typedef int zip_dig[ZLEN];
zip_dig_ku = {1, 9, 5, 3, 0};
int get_digit (zip_dig z, int digit) {
return z[digit];
}
Assembly code
# %rdi = z (starting address)
# %rsi = digit (index)
movl (%rdi, %rsi, 4), %eax # z[digit]
C code
void zincr(zip_dig z) {
size_t i;
for (i = 0; i < ZLEN; i++) {
z[i]++;
}
}
Assembly code
# %rdi = z
movl $0, %eax # i = 0
jmp .L3 # goto middle
.L4: # loop:
addl $1, (%rdi, %rax, 4) # z[i]++
addq $1, %rax # i++
.L3: # middle:
cmpq $4, %rax # i:4
jbe .L4 # if <=, goto loop
rep; ret
T A[R][C];
T
R
rows, C
columnsR * C * sizeof(T)
\[ \begin{bmatrix} \texttt{A[0][0]} & \dots & \texttt{A[0][C-1]}\\ \vdots & \ddots & \vdots\\ \texttt{A[R-1][0]} & \dots & \texttt{A[R-1][C-1]}\\ \end{bmatrix} \]
C code
#define PCOUNT 4
typedef int zip_dig[5];
zip_dig pgh[PCOUNT] =
{{1, 9, 5, 1, 1},
{1, 9, 5, 3, 6},
{1, 9, 5, 6, 2},
{1, 9, 5, 2, 9}};
A[i]
is array C
elements of type T
A + i * (C * sizeof(T))
A[i][j]
is element of type T
, which requies K
bytesA + i * (C* K) + j * k
\(\rightarrow\) A + (i * C + j) * K
C code
int *get_pgh_zip(int index) {
return pgh[index];
}
pgh[index]
is array of 5 int
values with starting address pgh + 20 * index
Assembly code
# %rdi = index
leaq (%rdi, %rdi, 4), %rax # 5 + index
leaq pgh(,%rax,4), %rax # pgh + (20 * index)
pgh + 4 * (index + 4 * index)
C code
int get_pgh_digit(int index, int dig) {
return pgh[index][dig];
}
Assembly code
leaq (%rdi, %rdi, 4), %rax # 5 + index
addl %rax, %rsi # 5 * index + dig
leaq pgh(,%rsi,4), %rax # M[pgh + 4 * (5 * index + dig)]
pgh[index][digit]
is a value of type int
pgh + 20 * index + 4 * dig
C code
zip_dig b = { 1, 9, 5, 1, 1};
zip_dig k = { 1, 9, 5, 3, 0};
zip_dig t = { 1, 9, 5, 6, 2};
#define TCOUNT 3
int *town[TCOUNT] = {b, k, t}
town
denotes an array of 3 elementsint
valuesC Code
int get_town_digit(size_t index, size_t digit) {
return town[index][digit]
}
Assembly Code
salq $2, %rsi # 4 * digit
addq town(, %rdi, 8), %rsi # p = town[index] + 4 * digit
movl (%rsi), %eax # return *p
Mem[Mem[town+8*index]+4*digit]
Fixed dimensions (know at compile time)
#define N 16
typedef int fix_matrix[N][N];
/* Get element at A[i][j] */
int fix_ele(fix_matrix A, size_t i, size_t j) {
return A[i][j];
}
Variable dimensions, explicit indexing
#define IDX(n, i, j) ((i)*(n)+(j))
/* Get element at A[i][j] */
int vec_ele(size_t n, int *A, size_t i, size_t j) {
return A[IDX(n,i,j)];
}
Variable dimensions, implicit indexing (now supported by gcc)
/* Get element at A[i][j] */
int vec_ele(size_t n, int A[n][n], size_t i, size_t j) {
return A[i][j];
}
int A[16][16];
A + i * (C * K) + j * K
C = 16
, K = 4
Assembly Code
# A in %rdi, i in %rsi, j in %rdx
salq $6, %rsi # 64 * i
addq %rsi, %rdi # A + 64 * i
movl (%rdi, %rdx, 4), %eax # Mem[A + 64*i + 4*j]
ret
size_t n;
int A[n][n];
A + i * (C * K) + j * K
C = n
, K = 4
Assembly Code
# n in %rdi, A in %rsi, i in %rdx, j in %rcx
imulq %rdx, %rdi # n * i
leaq (%rsi, %rdi, 4), %rax # A + 4*n*i
movl (%rax, %rcx, 4), %eax # A + 4*n*i + 4*j
ret
Example
struct rec {
int a[4]; // 16 bytes
size_t i; // 8 bytes
struct rec *next; // 8 bytes
}
C code
int *get_ap(struct rec *r, size_t, idx) {
return &r->a[idx];
}
Assembly code
# r in %rdi, idx in %rsi
leaq (%rdi, %rsi, 4), %rax
ret
r + 4 * idx
C Code
long length(struct rec* r) {
long len = 0L;
while (r) {
len++;
r = r->next;
}
return len;
}
Loop Assembly Code
.L11: # loop:
addq $1, %rax # len++
movq 24(%rdi), %rdi # r = Mem[r+24]
testq %rdi, %rdi # test r
jne .L11 # if != 0 goto loop
C Code
void set_val(struct rec* r, int val) {
while (r) {
size_t i = r->i;
// no bounds check
r->a[i] = val;
r = r->next;
}
}
Loop Assembly Code
.L11: # loop:
movq 16(%rdi), %rax # i = Mem[r+16]
movl %esi, (%rdi, %rax, 4) # Mem[r+4*i] = val
movq 24(%rdi), %rdi # r = Mem[r+24]
testq %rdi, %rdi # test r
jne .L11 # if != 0 goto loop
Example Code
struct S1 {
char c; // 1 byte
int i[2]; // 2*4 bytes
double v; // 8 bytes
} *p;
c
starts at address p
i[0]
starts at address p+1
i[1]
starts at address p+5
v
starts at address p+9
Example Code
struct S1 {
char c; // 1 byte
int i[2]; // 2*4 bytes
double v; // 8 bytes
} *p;
c
starts at address p+0
i[0]
starts at address p+4
(3-byte gap)i[1]
starts at address p+8
v
starts at address p+16
(4-byte gap)char
, \(\ldots\)
short
, \(\ldots\)
0
int
, float
, \(\ldots\)
00
double
, long
, char *
, \(\ldots\)
000
double
elementstruct S1 {
char c; // 1 byte
int i[2]; // 2*4 bytes
double v; // 8 bytes
} *p;
Overall structure must be multiple of K
Example
struct S2 {
double v; // 8 bytes
int i[2]; // 2*4 bytes
char c; // 1 byte
} *p;
char
is last, the overall structure needs 7 bytes of padding at the end.Example:
struct S2 {
double v; // 8 bytes
int i[2]; // 2*4 bytes
char c; // 1 byte
} a[10];
C code
struct S3 {
short i; // 2 bytes (2 byte gap)
float v; // 4 bytes
short j; // 2 bytes (2 byte padding)
} a[10];
short get_j(int idx) {
return a[idx].j;
}
Assembly code
# %rdi = idx
leaq (%rdi, %rdi, 2), %rax # 3*idx
movzwl a+8(,%rax,4), %eax # a+8 resolved at link time
Put large data types first
Example 1 (12 bytes total):
struct S4 {
char c; // 1 byte (3 byte gap)
int i; // 4 bytes
char d; // 1 byte (3 bytes padding)
} *p;
Example 2 (8 bytes total):
struct S5 {
int i; // 4 bytes
char c; // 1 byte (no gap)
char d; // 1 byte (2 bytes padding)
} *p;