Areas of memory
Running C and C++ programs are considered to have several segments or sections, distinct areas of memory.
- Text: For program code
- Data: For global and static variables
- Data (more specialized): For initialized variables
- BSS: For uninitialized variables — Required to be 0 in ANSI-C
- Stack: For local variables
- Heap: For dynamically allocated memory
Some compilers may place const variables in read-only segments. In some implementation each shared or dynamic-link library has its own segments for text and data. This allows several running programs to share common library routines.
Example C program using all areas
uint32_t Aglobal[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; const uint32_t Aconst[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; uint32_t Abss[10] ; void subr(void) { uint32_t ASlocal[10] ; return ; } int main(int argc, char** argv) { uint32_t AMlocal[10] ; uint32_t *Amalloc ; Amalloc = (uint32_t *)malloc(10*sizeof(uint32_t)) ; subr() ; return (EXIT_SUCCESS); }
Some address for those variables
Variable | 64-bit linux | 16-bit PIC |
---|---|---|
Aglobal | 0000000000600B00 | 0850 |
Aconst | 00000000004007A0 | 9072 |
Abss | 0000000000600B60 | 0878 |
Amalloc | 0000000000897010 | 09AE |
AMlocal | 00007FFF09C89C80 | 09F2 |
ASlocal | 00007FFF09C89C30 | 0A24 |
main | 0000000000400541 | 1204 |
subr | 0000000000400514 | 11EA |
printf | 00000000004003F8 | 0459 |
Pointers
Example C functions using pointers
void swap(int *p, int *q) { int t = *p ; *p = *q ; *q = t ; }
void sort(int *mn, int *mx) { if (*mn > *mx) { swap(&mn, &mx) ; } }
char *firstLetter(char *msg) { while (*msg && !isalpha(*msg)) { ++msg ; } return msg ; }
char *firstLetter(char *msg) { while (*msg && !isalpha(*msg++)) ; return msg ; }
Example C++ functions using references
void swap(int &p, int &q) { int t = p ; p = q ; q = t ; }
void sort(int &mn, int &mx) { if (mn > mx) { swap(mn, mx) ; } }
Examples of implementing pointers on the PIC
MOV x,W2 ;; W2 <- x MOV #x,W3 ;; W3 <- &x MOV [W3],W2 ;; W2 <- *W3 MOV W5,[W3] ;; *W3 <- W5 MOV [W6],[W7] ;; *W7 <- *W6 MOV [W8++],[++W9] ;; *++W9 <- *W8++
Arrays and pointers in C
In C, an array declaration defines a constant pointer
to a sequence of data values. For example:
int A[] = {2, 3, 5} ;
is really the same type as:
int * const A = {2, 3, 5} ;
In neither case can A
be assigned a value.
However, A[4]
can be modified.
Incidentally, these declarations are not the same as:
const int A[] = {2, 3, 5} ;
or
const int * A = {2, 3, 5} ;
Neither of these declarations allow assignments to
A[4]
can be modified.
Finally, all you Java programmers should be warned that the following,
while encouraged in Java, is forbidden in C:
int[] A = {2, 3, 5} ;
In C the brackets must follow the variable name.
Pointer arithmetic in C
If p is the address of an integer in C, then
p+i is the address of the i’th
integer stored in memory after the place p points to.
This interpretation means that p[i]
can be
considered an abbreviation for *(p+i)
.
Two equivalent C loops
for (i=0; i<1000; ++i) { A[i] = B[i] ; }
int *pA = &A[0] ; int *pB = &B[0] ; for (i=0; i<1000; ++i) { *pA++ = *pB++ ; }
In the old days programmers obsessed with efficiency would often write obfuscated loops using pointer arithmetic. Today, optimizing compiler use techniques, such as loop unrolling, that produce faster code than the “hand optimized” code.
C Strings
In C a string is an array of characters, but instead of having a size it is terminated by a null character.
char maxC = '\0' ; char *nextC = &buff[0] ; while (*nextC != '\0') { if (*nextC > maxC) { maxC = *nextC ; } ++nextC ; }
Examples of implementing arrays on the PIC
Assume that c
is an array of 8-bit characters.
Each character will require one byte.
MOV.B W2,x+5 ;; c[5] <- W2 MOV.B x+5,W2 ;; W2 <- c[5] MOV.B W2,[W4+5] ;; W4[5] <- W2 MOV.B [W4+5],W2 ;; W2 <- W4[5] MOV.B [W4+W5],W2 ;; W2 <- W4[W5]
Now, assume that x
is an array of 16-bit integers.
Each integer will require two bytes.
MOV W2,x+10 ;; x[5] <- W2 MOV x+10,W2 ;; W2 <- x[5] MOV W2,[W4+10] ;; W4[5] <- W2 MOV [W4+10],W2 ;; W2 <- W4[5] ADD W5,W5,W0 ;; MOV [W4+W0],W2 ;; W2 <- W4[W5]
Getting the right address
The following two lines of PIC code will increase the value stored
in W7
by one and the value stored in
W8
by two.
MOV.B [++W7],W0 MOV [++W8],W0
Faster loops
The PIC instruction set has a REPEAT
instruction
that is designed to make loops a bit more succinct.
Here is an implementation of
the C for
shown above that copied the first
1000 elements of B
into A
.
MOV #A,W5 MOV #B,W6 REPEAT #999 MOV [W6++],[W5++]
A brief look at structure
C has a non-heterogeneous data structure called the struct
,
resembling a method-less class in Java, where several fields
are stored within a collection.
struct point3D { int x ; int y ; int z ; } struct point3D P ; P.x = 5 ; P.y = P.x + 1 ; P.z = 7 ;
When implemented the fields are stored at fixed offsets from the beginning of the structure.
MOV P+2,W5 ;; W5 <- P.y MOV W5,P+4 ;; P.z <- W5
Trying out an example
int V[500] ; int H[100] ; int i ; for (i=0; i<100; ++i) { H[i] = 0 ; } for (i=0; i<500; ++i) { ++H[V[i]] ; }