-
Notifications
You must be signed in to change notification settings - Fork 0
L15 [Continuing With C]
- Preprocessor takes C source code and turns it into Preprocessed source code
- Expands #include statements
- Compiler takes Preprocessed Source Code and turns it into Object Files
- Linkers links the Object Files and Library Files and turns it into Machine Language Executables
- Text
- Program code (unmodifiable)
- Constant data (maybe)
- Data
- Constant data (maybe)
- Initialized variables
- BSS
- Uninitalized static data
- From "Block Starting With Symbol"
-
.blkw
from LC-3
Table
- Function - program text
- Global variables - data segment
- Static variables - data segment
- Local variables - stack
- Dynamically allocated - heap
-
static
means visible to no other files -
extern
means visible to other files - declares reference to an external definition elsewhere -
<no keyword>
means External definition (visible to other files)
From something like file1.c
int a[10]; //External definition
static struct r *p; //This file only
extern float c[100]; //ref to c in file2.c
And in file2.c
extern int a[10]; // Ref to arr in file1.c
static struct r *p; // NOT the p in file1
float c[100]; // Definition
Storage class tells us where the data will be stored and who will be able to see it
Remember: it is NOT part of the type
The rules for storage classes are NOT regular; you will need to memorize them or have a steady reference
-
auto
- automatic duration and no linkage -
register
- automatic duration and no linkage; address of this variable cannot be taken -
static
- static duration and internal linkage (unless at block scope) -
extern
- static duration and external linkage (unless already declared internal)
Remember: static has different meanings
- Inside a function - static changes the storage location to static memory, either data or BSS segment (the scope stays local)
- Outside a function - static changes the scope (visibility) to be only visible within the file (the storage location stays in static memory)
- static defined functions are not visible outside of its C file
Extern
- Compiler does NOT allocate storage
- For type checking of the identifier name only
- Another C file must allocate storage by defining that var name (or function)
- Note that you cannot initialize an extern variable in the same name, e.x.
extern int i = 3;
- Note that you cannot initialize an extern variable in the same name, e.x.
Global Variables
- By default, global variables are static storage duration and external linkage
-
const
- the value of this variable may not be changed after initialization -
volatile
- the compiler may not optimize references to this variable (e.g. it’s a device register that may change value asynchronously) -
restrict
- For the lifetime of a pointer, only the pointer itself or a value directly derived from it may be used to access the object to which it points. This allows better optimization.
Volatile
- Tells the compiler not to optimize away the variable
- Use this for device registers
A declaration in C introduces an identifier and describes its type, be it a scalar, array, struct, or function. A declaration is what the compiler needs to accept references to that identifier (for type checking).
A definition in C actually instantiates/implements this identifier. For instance, a definition allocates storage for variables or defines the body of a function.
Example
static volatile long int i, *j, k[10];
i is a volatile long int, j is a pointer to a volatile long int, and k is an array[10] of volatile long int
Remember, each declarator is separate
int *x, y, z;
y is NOT a pointer, only x is
- Remember the precedence of declarators
- () and [] declarators get processed first
-
- gets processed last
- Parentheses change the precedence order
- Read or form the declarations from the inside out
Example: `int *(**f)()
- f is a pointer to a pointer of a function that returns a pointer to an int
Step by step
-
*f
means pointer to -
(**)f
means pointer to pointer -
(**f)()
means pointer to pointer to a function -
*(**f)()
means pointer to pointer to a function that returns a pointer -
int *(**)f()
means pointer to pointer to a function that returns a pointer
Parsing: determining which grammar productions (rules) were used to generate a sentence
- Try out
dcl.c
in Canvas > Files > Source Code
Typedef is a shortcut that allows you to create a new alias for a type
- Does NOT create a new type
- Start the declaration with "typedef" and put hte alias name where you would put the variable name
- Really just creates another name for an existing type
struct a b[5]; //Array of 5 struct a named b
typedef struct a sa5[5]; //Create type alias for an array of 5 struct a
sa5 c;
- Functions must be declared before they are used
- Function prototype:
int nfact(int);
- A function prototype is automatically given the extern storage class
- Parameters are always passed as call-by-value
- Copies of the parameters (even structs) are pushed onto the stack
- Arrays turn into pointers to their first element, a copy of which is passed
- Manual bounds checking
sizeof(ary) / sizeof(ary[0])
- If it's passed as a parameter, you need another parameter for the length
- Arrays and all C variables are always allocated in a single contiguous memory block
-
short matrix[10][10][10]
would assemble asmatrix .blkw 1000
-
Any array element selection you can do using subscripts can be done with pointers and pointer arithmetic
-
*(p+n)
is literally the same asp[n]
(or more surprisinglyn[p]
)
int ib[5] = { 5, 4, 3, 2, 1 };
int ib[] = { 5, 4, 3, 2, 1 };
char cb[] = { ‘x’, ‘y’, ‘z’ };
char cb[] = “hello”;
Notes about sizeof
char c1[] = “hello”;
char *c2 = “hello”;
sizeof(c1); //sizeof(c1) == 6
sizeof(c2); //sizeof(c2) == 8, the size of a pointer on your system
strlen(c1) == strlen(c2); //strlen(c1)==5==strlen(c2)
Note that "hello"
from c2 would be stored in Constant Data but everything else (*c2, c1[], and "hello" from c1[]) will be stored as Initalized Data
Why is this?
char *c2 = “hello”;
In this case, the pointer value can be changed, but "hello" cannot be changed.
However, for
char c1[] = “hello”;
The pointer value cannot be changed, but "hello" can be changed.
Let's you you have int ia[6];
How much space is allocated?
6 * sizeof(int) == 24
So then, ia[4]
is quite literally 4 * 4 + address of array
Let's say you wrote this code
int ia[6];
ia[3] = 42;
Now, ia[3]
is the same as *(ia + 3) = 42;
, and *(3 + ia) = 42;
Someone might think that this would imply 3[ia] = 42;
, which is dumb but works.