ADVANCED C - PowerPoint PPT Presentation

1 / 117
About This Presentation
Title:

ADVANCED C

Description:

... faster than multiplying (but good ol' multiplication makes for much clearer code) ... Structure in C is a collection of items of different types. ... – PowerPoint PPT presentation

Number of Views:29
Avg rating:3.0/5.0
Slides: 118
Provided by: webIi
Category:

less

Transcript and Presenter's Notes

Title: ADVANCED C


1
ADVANCED C
  • Sushma
  • Ukil

2
Memory Management
  • A process is an "invocation" or "activation" of a
    program. A program is a list of instructions for
    execution by a computer.
  • To run the program it needs to be copied (or
    loaded) into the main computer memory and the
    central processing unit is told to start reading
    (and obeying) instructions taken from that area
    of memory. The activity of executing the
    program's instructions is called running the
    process.
  • A portion of memory needs to be allocated to a
    process. The actual allocation of such an area of
    memory is a task for the loader.
  • The memory area allocated to a program will
    usually be split into several sub-areas for
    particular.

3
Memory management
  • The code segment
  • This is known as the text area in Unix parlance
    and simply contains the executable code of the
    program(both the program binary and any shared
    library it loads).
  • If there are several processes running the same
    program there will still only be one code area as
    it is identical for all processes.
  • The current state of a process is determined by
    its various data areas.
  • All memory pages of code segment are marked as
    read-only and are shared with any other process
    using the same program file and/or shared library
    files.
  • The kernel process exchange (or switch) mechanism
    will activate a particular process by indicating
    to the hardware where the next instruction is to
    be read from what mapping is to be used to access
    data

4
Memory Management
  • The data segment
  • This holds the data being processed by the
    program, it's size is initially determined by the
    loader from information in the binary file which
    specifies the amount of initialized data to be
    copied form the binary file and the amount of un
    initialized space to be allocated to the process.
  • On some systems the space may be initialized to
    zero but this is not universal and such areas may
    contain "droppings" left over from previous
    processes, a possible security problem. On older
    Unix systems the un initialized space is known as
    bss from a PDP/11 assembler mnemonic.
  • The Unix size command will give the memory
    requirement information for a binary file.
  • This segment can grow as the process runs and
    needs more virtual memory.
  • bash size testhand2 92763 7564 2320 102647
  • The above example shows that loading the binary
    file testhand2 will require 102647 bytes of
    memory with 92763 bytes for code, 7564 bytes for
    initialized data and 2320 bytes for
    non-initialized data.

5
Memory Management
  • The stack segment
  • Whenever a function is called a stack frame is
    created to store data related to the current
    invocation of the function such as the return
    address, saved state, local copies of parameters
    and, of course, local data.
  • The stack is normally built within the data area
    of the process and the memory allocated to the
    stack can be expanded as needed.
  • The stack and the arena need to be kept separate
    from the initialized and un initialized data
    areas, this is normally achieved by using widely
    separated parts of a large virtual address space.

6
Memory Management
  • Heap memory
  • The heap is a portion of memory allocated
    dynamically (as needed, at runtime) for the use
    of the process.
  • Whenever the malloc or calloc functions are used
    in C for instance, they reserve space in heap
    memory.
  • Stack
  • The stack portion of memory, on the other hand,
    is used by the process to aid the invocation of
    functions.
  • Every time a function is called, the process
    reserves a portion of stack memory to store the
    values of parameters passed to the functions as
    well as for results returned by the functions and
    the local variables used within the functions.
  • The stack is also where space for all declared
    data types and structures is reserved at compile
    time.

7
Memory Management
  • The Stack And Local Variables
  • The stack is used by the process to store the
    chain of functions which are currently in the
    middle of execution.
  • Each function call causes the process to add an
    execution frame to the top of the stack. This
    execution frame would contain the contents of CPU
    registers as they were before the function call
    was made, the return address (i.e. where in the
    code this function was invoked, so we can return
    there when the function returns), the parameters
    passed to the function and all local variables of
    the function.
  • Thus, when we have function 'main' calling
    function 'a' which calls function 'b', we will
    have 3 frames on the stack.
  • The 'allocation' of a stack frame does not
    require performing real memory allocation - as
    the space for the stack was reserved during
    process startup. Instead, this is done by merely
    marking a part of the stack as containing the
    frame, and copying data to that frame.
  • Note that local variables are "allocated" by
    simply advancing the stack pointer beyond their
    location on the stack, so allocating local
    variables takes a fixed amount of time, no matter
    their size.
  • When a function returns - its stack frame is
    freed by simply modifying the stack pointer to
    point below its frame.

8
Memory Management
  • The Stack And Local Variables(cont..)
  • The local variables are not initialized - they
    just contain the values that were accidentally
    placed in the memory locations these variables
    occupy.
  • Consider a situation in which a function was
    called, its variables used and given some values.
  • Later the function returned, and its frame was
    released.
  • Then, another function was called.
  • The stack frame of this new function is located
    in the same place in memory as the frame of the
    former function, so the new function's local
    variables will get the values that were left
    there by the local variables of the former
    function.
  • This can explain why the values of un initialized
    local variables are often neither 0, nor look
    like total garbage.
  • Since all local variables are stored in
    consecutive memory on the stack, if we take a
    pointer to such a variable, and later on write
    right above or right below this pointer, we'll be
    modifying the contents of another local variable,
    or even that of the function's return address.

9
Memory Management
  • The Stack And Local Variables(cont..)
  • For example, consider the following code
  • int foo()
  • int numbers2
  • int j j 2
  • printf("j - d\n", j)
  • numbers2 3
  • printf("j - d\n", j)
  • During execution of this function, we first
    assign 2 to 'j', and thus the first print command
    will show "j - 2". Then, we try to assign a value
    to 'numbers2'. However, the 'numbers' array
    only has 2 cells - 0 and 1. Writing into
    subscript '2' of this array will cause us to
    write just beyond the array (which is fully
    located on the stack).
  • The variable 'j' just happens to be stored in
    that location in memory, and thus, the value '3'
    will be actually assigned to 'j'.
  • Our second print command will thus show "j - 3".

10
Memory Management
  • The Stack And Local Variables(cont..)
  • Note that this assumes that the variables are
    stored in memory in the same order as they were
    declared inside the function's code. With some
    compilers, this might not be the case, and the
    out-of-range assignment might overwrite a
    different variable, or a part of the stack that
    does not hold variables, leading to other
    unexpected results.
  • Note local variables (as well as function
    parameters) might be stored in registers, rather
    than on the stack. This could be either because
    we used the 'register' keyword when declaring
    these variables, or because the compiler's
    optimization chose to place a variable in a
    register. Of course, such variables cannot be
    over-written by stack overflows.

11
Memory Management
  • Dynamic Memory Allocation
  • Memory can be allocated dynamically by the calls
  • malloc()
  • calloc()
  • realloc()
  • The prototype for malloc is
  • void malloc(size_t size)
  • malloc takes in a size_t and returns a void
    pointer.
  • Why does it return a void pointer? Because it
    doesn't matter to malloc to what type this memory
    will be used for.
  • Let's see an example of how malloc is used
  • int ip
  • ip malloc(5 sizeof(int)) / .. OR .. /
  • ip malloc(5 sizeof(ip))
  • Pretty simplistic. sizeof(int) returns the sizeof
    an integer on the machine, multiply by 5 and
    malloc that many bytes.
  • The second malloc works because it sends what ip
    is pointing to, which is an int.

12
Memory Management
  • Dynamic Memory Allocation(cont..)
  • Wait... we're forgetting something. AH! We didn't
    check for return values.
  • Here's some modified code
  • define INITIAL_ARRAY_SIZE 5
  • / ... code ... /
  • int ip
  • if ((ip malloc(INITIAL_ARRAY_SIZE
    sizeof(int))) NULL)
  • (void)fprintf(stderr, "ERROR Malloc failed")
    (void)exit(EXIT_FAILURE) / or return
    EXIT_FAILURE /
  • Now our program properly prints an error message
    and exits gracefully if malloc fails.

13
Memory Management
  • Dynamic Memory Allocation(cont..)
  • calloc works like malloc, but initializes the
    memory to zero if possible.
  • The prototype is
  • void calloc(size_t nmemb, size_t size)
  • bzero fills the first n bytes of the pointer to
    zero.
  • Prototype
  • void bzero(void s, size_t n)
  • If you need to set the value to some other value
    (or just as a general alternative to bzero), you
    can use memset
  • void memset(void s, int c, size_t n)
  • where you can specify c as the value to fill for
    n bytes of pointer s.

14
Memory Management
  • Dynamic Memory Allocation(cont..)
  • What if we run out of allocated memory during the
    run-time of our program and need to give our
    collection of items more memory?
  • Use realloc, it's prototype
  • void realloc(void ptr, size_t size)
  • realloc takes in the pointer to the original area
    of memory to enlarge and how much the total size
    should be.
  • So let's give it a try
  • ip realloc(ip, sizeof(ip) sizeof(int)5)
  • Ah... Now we have some more space, by simply
    giving it the sizeof the complete array and then
    adding 5 spaces for ints.
  • "I'm a genius!" you say... and then your program
    segfaults, core dumps and you get laughed at.
  • STOP! This is NOT how you use realloc.
  • Again. The above example is wrong. Why?

15
Memory Management
  • Dynamic Memory Allocation(cont..)
  • First, sizeof(ip) does not give the size of the
    allocated space originally allocated by malloc
    (or a previous realloc).
  • Using sizeof() on a pointer only returns the
    sizeof the pointer, which is probably not what
    you intended.
  • Also, what happens if the realloc on ip fails?
    ip gets set to NULL, and the previously allocated
    memory to ip now has no pointer to it.
  • Now we have allocated memory just floating in the
    heap without a pointer. This is called a memory
    leak. This can happen from sloppy realloc's and
    not using free on malloc'd space. So what is the
    correct way? Take this code for example
  • int tmp
  • if ((tmp realloc(ip, sizeof(int)
    (INITIAL_ARRAY_SIZE 5))) NULL)
  • / Possible free on ip? Depends on what you want
    /
  • fprintf(stderr, "ERROR realloc failed")
  • ip tmp

16
Memory Management
  • Dynamic Memory Allocation(cont..)
  • Now we are creating a temporary pointer to try a
    realloc. If it fails, then it isn't a big problem
    as we keep our ip pointer on the original memory
    space.
  • Also, note that we specified the real size of our
    original array and now are adding 5 more ints (so
    4bytes(55) 40bytes, on a typical 32-bit
    machine).
  • Now that we can malloc, calloc, and realloc we
    need to be able to free the memory space if we
    have no use for it anymore. Like we mentioned
    above, any memory space that loses its pointer or
    isn't free'd is a memory leak.
  • So what's the prototype for free? Here it is
  • void free(void ptr)
  • free simply takes in a pointer to free. Not
    challenging at all. Note that free can take in
    NULL, as specified by ANSI.

17
Memory Management
  • Assigning memory to segments
  • Compiler and assembler generate an object file
    (containing code and data segments) from each
    source file
  • Linker combines all the object files for a
    program into a single executable object file,
    which is complete and self-sufficient
  • Loader (part of OS) loads an executable object
    file into memory at location(s) determined by the
    operating system
  • Program (as it runs) uses new and malloc to
    dynamically allocate memory, gets space on stack
    during function calls

18
Memory Management
  • Linking
  • Functions of a linker
  • Combine all files and libraries of a program
  • Regroup all the segments from each file together
    (one big data segment, etc.)
  • Adjust addresses to match regrouping
  • Result is an executable program
  • Contents of object files
  • File header size and starting address(in
    memory) of each segment
  • Segments for code and initialized data
  • Symbol table (symbols, addresses)
  • External symbols (symbols, location)
  • Relocation information (symbols, location)
  • Debugging information
  • For UNIX details, type man a.out

19
Memory Management
  • Why is Linking Difficult?
  • When assembler assembles a file, it may find
    external references symbols it doesnt know
    about (e.g., printf, scanf)
  • Compiler just puts in an address of 0 when
    producing the object code
  • Compiler records external symbols and their
    location (in object file) in a crossreference
    list, and stores that list in the object file
  • Linker must resolve those external references as
    it links the files together
  • Compiler doesnt know where program will go in
    memory (if multiprogramming, always 0 for
    uniprogramming)
  • Compiler just assumes program starts at 0
  • Compiler records relocation information (location
    of addresses to be adjusted later), and stores it
    in the object file

20
Memory Management
  • Loading
  • The loader loads the completed program into
    memory where it can be executed
  • Loads code and initialized data segments into
    memory at specified location
  • Leaves space for uninitialized data (bss)
  • Returns value of start address to operating
    system
  • Alternatives in loading
  • Absolute loader loads executable file at fixed
    location
  • Relocatable loader loads the program at an
    arbitrary memory location specified by OS (needed
    for multiprogramming, not for uniprogramming)
  • Assembler and linker assume program will start at
    location 0
  • When program is loaded, loader modifies all
    addresses by adding the real start location to
    those addresses

21
Memory Management
  • Running the Program Static Memory Allocation
  • Compiling, linking, and loading is sufficient for
    static memory
  • Code, constants, static variables
  • In other cases, static allocation is not
    sufficient
  • Need dynamic storage programmer may not know
    how much memory will be needed when program runs
  • Use malloc or new to get whats necessary when
    its necessary
  • For complex data structures (e.g., trees),
  • allocate space for nodes on demand
  • OS doesnt know in advance which procedures will
    be called (would be
  • wasteful to allocate space for every variable in
    every procedure in advance)
  • OS must be able to handle recursive procedures

22
Memory management
  • Running the Program Dynamic Memory Allocation
  • Dynamic memory requires two fundamental
    operations
  • Allocate dynamic storage
  • Free memory when its no longer needed
  • Methods vary for stack and heap
  • Two basic methods of allocation
  • Stack (hierarchical)
  • Good when allocation and freeing are somewhat
    predictable
  • Typically used
  • to pass parameters to procedures
  • for allocating space for local variables inside a
    procedure
  • for tree traversal, expression evaluation,parsing,
    etc.
  • Use stack operations push and pop
  • Keeps all free space together in a structured
    organization
  • Simple and efficient, but restricted

23
Memory Management
  • Running the Program Dynamic Memory Allocation
    (cont.)
  • Two basic methods of allocation
  • Heap
  • Used when allocation and freeing are not
    predictable
  • Typically used
  • for arbitrary list structures, complex data
    organizations, etc.
  • Use new or malloc to allocate space, use delete
    or free to release space
  • System memory consists of allocated areas and
    free areas (holes)
  • Problem eventually end up with many small holes,
    each too small to be useful
  • This is called fragmentation, and it leads to
    wasted memory
  • Fragmentation wasnt a problem with stack
    allocation, since we always add/delete from top
    of stack
  • Solution goal reuse the space in the holes in
    such a way as to keep the number of holes small,
    and their size large
  • Compared to stack more general, less efficient,
    more difficult to implement

24
Strings
  • Stings in C are stored as null character, '\0',
    terminated character arrays.
  • This means that the length of a string is the
    number of characters it contains plus one to
    store the null character.
  • The subscripts used for the array start with zero
    (0).
  • Common string operations include finding lengths,
    copying, searching, replacing and counting the
    occurrences of specific characters and words.
  • include ltstring.hgt needs to be included when
    string functions are used
  • The following line declares a char array called
    str.
  • char str15
  • C provides fifteen consecutive bytes of memory.
  • Only the first fourteen bytes are usable for
    character storage, because one must be used for
    the string-terminating null.
  • The following is a representation of what would
    be in RAM, if the string "Hello, world!" is
    stored in this array.
  • Characters H e l l o , w o
    r l d !
  • Hex values 48 65 6C 6C 6F 2C 20 77 6F 71 6C 64
    21 00
  • Subscripts 0 1 2 3 4 5 6 7
    8 9 10 11 12 13 14

25
Strings
  • Common String Functions
  • strcpystrcpy copies a string, including the
    null character terminator from the source string
    to the destination. This function returns a
    pointer to the destination string, or a NULL
    pointer on error. Its prototype ischar
    strcpy(char dst, const char src)strncpystrn
    cpy is similar to strcpy, but it allows the
    number of characters to be copied to be
    specified. If the source is shorter than the
    destination, than the destination is padded with
    null characters up to the length specified. This
    function returns a pointer to the destination
    string, or a NULL pointer on error. Its prototype
    ischar strncpy(char dst, const char src,
    size_t len)strcatThis function appends a
    source string to the end of a destination string.
    This function returns a pointer to the
    destination string, or a NULL pointer on error.
    Its prototype ischar strcat(char dst, const
    char src)

26
Strings
  • Common String Functions(Cont..)
  • strncatThis function appends at most N
    characters from the source string to the end of
    the destination string. This function returns a
    pointer to the destination string, or a NULL
    pointer on error. Its prototype ischar
    strncat(char dst, const char src, size_t
    N)strcmpThis function compares two strings.
    If the first string is greater than the second,
    it returns a number greater than zero. If the
    second string is greater, it returns a number
    less than zero. If the strings are equal, it
    returns 0. Its prototype isint strcmp(const
    char first, const char second)strncmpThis
    function compares the first N characters of each
    string. If the first string is greater than the
    second, it returns a number greater than zero. If
    the second string is greater, it returns a number
    less than zero. If the strings are equal, it
    returns 0. Its prototype isint strncmp(const
    char first, const char second, size_t N)

27
Strings
  • Common String Functions(Cont..)
  • strlenThis function returns the length of a
    string, not counting the null character at the
    end. That is, it returns the character count of
    the string, without the terminator. Its prototype
    issize_t strlen(const char str)
  • strchr
  • This function finds the first occurrence of
    character C in string STR, returning a pointer to
    the located character. It returns NULL pointer
    when there is no match
  • char strchr (char STR, char C)
  • strstr
  • This function is like strchr' but searches for
    string SEARCH in string STR, returning a pointer
    into the STR that is the first character of the
    match found in STR. It returns NULL pointer if no
    match was found. If SEARCH is an empty string, it
    returns STR.
  • char strstr (const char STR, const char
    SEARCH)

28
Bitwise Operators
  • Bitwise operators apply the same operation to
    matching bits in value on each side of operator
    (the one's complement is unary and works only on
    the value to it's right)
  • Result for each bit position determined only by
    the bit(s) in that position
  • Results for each operator summarized in the
    following table

29
Bitwise Operators
  • Shift Operators
  • Operators gtgt and ltlt can be used to shift the bits
    of an operand to the right or left a desired
    number of positions
  • The number of positions to be shifted can be
    specified as a constant, in a variable or as an
    expression
  • Can be used on any of the integral data types -
    char, short, ltVARINTlt VARgtor long
  • Bits shifted out are lost
  • For left shifts, bit positions vacated by
    shifting always filled with zeros
  • For right shifts, bit positions vacated by
    shifting filled
  • with zeros for unsigned data type
  • with copy of the highest (sign) bit for signed
    data type
  • Applications
  • quick multiplication by a power of 2
  • quick division by power of 2 (unsigned types
    only)
  • bit-mapped record processing
  • packing / unpacking data less that byte size

30
Bitwise Operators
  • Shift operators(contd..)
  • Can use ltlt to multiply integral value by a power
    of two
  • 1 bit multiplies by 2, 2 bits multiplies by 4, 3
    bits multiplies by 8, n bits multiplies by 2n
  • On some implementations, shifting may be much
    faster than multiplying (but good ol'
    multiplication makes for much clearer code)
  • Using left shift to multiply
  • long x 75, y
  • int i
  • ...
  • x ltlt 2 / x 75 4 300 /
  • y x ltlt 1 / y ( x 2 600 ) x is not
    changed /
  • x 6
  • for ( i 0 i lt 5 i )
  • printf( "d\n", x ltlt i )
  • Prints
  • 6 6 ltlt 0 is 61
  • 12 6 ltlt 1 is 62
  • 24 6 ltlt 2 is 64

31
Bitwise Operators
  • Shift operators(contd..)
  • Can use gtgt to divide unsigned integral value by a
    power of two.
  • 1 bit divides by 2, 2 bits divides by 4, 3 bits
    divides by 8, n bits divides by 2n
  • On some implementations, shifting may be much
    faster than dividing (but division makes for much
    clearer code)
  • Shifting signed values may fail because for
    negative values the result never gets past -1
  • -5 gtgt 3is -1 and not 0 like -5/8
  • Using right shift to divide
  • unsigned long x 75, y
  • ...
  • x gtgt 2 / x 75 / 4 18 /
  • y x gtgt 1 / y ( x / 2 9 ) x is not changed
    /

32
Structures
  • Structure in C is a collection of items of
    different types. You can think of a structure as
    a "record" is in Pascal or a class in Java
    without methods.
  • So how is a structure declared and initialized?
    Let's look at an example
  • struct student
  • char first
  • char last
  • char SSN9
  • float gpa
  • char classes
  • struct student student_a, student_b
  • Structures Declaration and Syntax

33
Structures
  • Another way to declare the same thing is
  • struct
  • char first
  • char last
  • char SSN10
  • float gpa
  • char classes
  • student_a, student_b
  • As you can see, the tag immediately after struct
    is optional. But in the second case, if you
    wanted to declare another struct later, you
    couldn't.

34
Structures
  • The "better" method of initializing structs is
  • struct student_t
  • char first
  • char last
  • char SSN10
  • float gpa
  • char classes
  • student, pstudent
  • Now we have created a student_t student and a
    student_t pointer. The pointer allows us greater
    flexibility (e.g. Create lists of students).
  • You could initialize a struct just like an array
    initialization. But be careful, you can't
    initialize this struct at declaration time
    because of the pointers.
  • To access fields inside struct C has a special
    operator for this called "member of" operator
    denoted by . (period). For example, to assign the
    SSN of student_a strcpy(student_a.SSN,
    "111223333\0")

35
Structures
  • Nested structures
  • Structures can contain other structures as
    members in other words, structures can nest.
    Consider the following two structure types
  • struct first_structure_type
  • int integer_member
  • float float_member
  • struct second_structure_type
  • double double_member
  • struct first_structure_type struct_member
  • The first structure type is incorporated as a
    member of the second structure type.

36
Structures
  • Nested structures(Contd..)
  • You can initialize a variable of the second type
    as follows struct second_structure_type demo
  • demo.double_member 12345.6789
    demo.struct_member.integer_member 5
    demo.struct_member.float_member 1023.17
  • The member operator . is used to access members
    of structures that are themselves members of a
    larger structure.
  • No parentheses are needed to force a special
    order of evaluation
  • A member operator expression is simply evaluated
    from left to right.
  • In principle, structures can be nested
    indefinitely.

37
Typedef
  • There is an easier way to define structs or you
    could "alias" types you create.
  • For example
  • typedef struct
  • char first
  • char last
  • char SSN9
  • float gpa
  • char classes
  • student student student_a
  • Now we get rid of those silly struct tags. You
    can use typedef for non-structs typedef long int
    pint32 pint32 x, y, z x, y and z are all
    pointers to long ints. typedef is your friend.
    Use it.

38
Union
  • Unions are declared in the same fashion as
    structs, but have a fundamental difference. Only
    one item within the union can be used at any
    time, because the memory allocated for each item
    inside the union is in a shared memory location.
    Why you ask? An example first
  • struct conditions
  • float temp
  • union feels_like
  • float wind_chill
  • float heat_index
  • today
  • As you know, wind_chill is only calculated when
    it is "cold" and heat_index when it is "hot".
    There is no need for both. So when you specify
    the temp in today, feels_like only has one value,
    either a float for wind_chill or a float for
    heat_index.
  • Types inside of unions are unrestricted, you can
    even use structs within unions.

39
Enum
  • What if you wanted a series of constants without
    creating a new type? Enter enumerated types. Say
    you wanted an "array" of months in a year
  • enum e_months JAN1, FEB, MAR, APR, MAY, JUN,
    JUL, AUG, SEP, OCT, NOV, DEC
  • typedef enum e_months month
  • month currentmonth
  • currentmonth JUN / same as currentmonth 6
    /
  • printf("d\n", currentmonth)
  • We are enumerating the months in a year into a
    type called month. You aren't creating a type,
    because enumerated types are simply integers.
    Thus the printf statement uses d, not s.
  • If you notice the first month, JAN1 tells C to
    make the enumeration start at 1 instead of 0.
  • Note This would be almost the same as using
  • define JAN 1
  • define FEB 2
  • define MAR 3 / ... etc ... /

40
Static Variables
  • A static variable is local to particular
    function. However, it is only initialised once
    (on the first call to function).
  • Also the value of the variable on leaving the
    function remains intact. On the next call to the
    function the the static variable has the same
    value as on leaving.
  • To define a static variable simply prefix the
    variable declaration with the static keyword. For
    example
  •   void stat() / prototype fn /   main()   
    int i   for (i0ilt5i) stat()      stat()
       int auto_var 0 static int static_var 0
      printf( auto d, static d n'',
    auto_var, static_var) auto_var static_var
      
  • Output is
  •   auto_var 0, static_var 0 auto_var 0,
    static_var 1 auto_var 0, static_var 2
    auto_var 0, static_var 3 auto_var 0,
    static_var 4
  • Clearly the auto_var variable is created each
    time. The static_var is created once and
    remembers its value.

41
Bitfields
  • Bit Fields allow the packing of data in a
    structure. This is especially useful when memory
    or data storage is at a premium. Typical
    examples
  • Packing several objects into a machine word.
  • e.g. 1 bit flags can be compacted -- Symbol
    tables in compilers.
  • Reading external file formats -- non-standard
    file formats could be read in. E.g. 9 bit
    integers.
  • C lets us do this in a structure definition by
    putting bit length after the variable. i.e.
  • struct packed_struct
  • unsigned int f11
  • unsigned int f21
  • unsigned int f31
  • unsigned int f41
  • unsigned int type4
  • unsigned int funny_int9
  • pack
  • Here the packed_struct contains 6 members Four 1
    bit flags f1..f3, a 4 bit type and a 9 bit
    funny_int.

42
Bitfields
  • C automatically packs the above bit fields as
    compactly as possible, provided that the maximum
    length of the field is less than or equal to the
    integer word length of the computer. If this is
    not the case then some compilers may allow memory
    overlap for the fields whilst other would store
    the next field in the next word
  • NOTE
  • Only n lower bits will be assigned to an n bit
    number. So type cannot take values larger than 15
    (4 bits long).
  • Bit fields are always converted to integer type
    for computation.
  • You are allowed to mix normal'' types with bit
    fields.
  • The unsigned definition is important - ensures
    that no bits are used as a flag.

43
Bitfields
  • Bit Fields Practical Example
  • Frequently device controllers (e.g. disk drives)
    and the operating system need to communicate at a
    low level. Device controllers contain several
    registers which may be packed together in one
    integer  
  • We could define this register easily with bit
    fields
  • struct DISK_REGISTER
  • unsigned ready1
  • unsigned error_occured1
  • unsigned disk_spinning1
  • unsigned write_protect1
  • unsigned head_loaded1
  • unsigned error_code8
  • unsigned track9 u
  • nsigned sector5
  • unsigned command5
  • To access values stored at a particular memory
    address, DISK_REGISTER_MEMORY we can assign a
    pointer of the above structure to access the
    memory via
  • struct DISK_REGISTER disk_reg (struct
    DISK_REGISTER ) DISK_REGISTER_MEMORY

44
Bitfields
  • The disk driver code to access this is now
    relatively straightforward
  • / Define sector and track to start read /
  • disk_reg-gtsector new_sector
  • disk_reg-gttrack new_track
  • disk_reg-gtcommand READ / wait until operation
    done, ready will be true /
  • while ( ! disk_reg-gtready ) / check for errors
    /
  • if (disk_reg-gterror_occured)
  • / interrogate disk_reg-gterror_code for error
    type /
  • switch (disk_reg-gterror_code) ......
  • A note of caution Portability
  • Bit fields are a convenient way to express many
    difficult operations. However, bit fields do
    suffer from a lack of portability between
    platforms
  • integers may be signed or unsigned

45
Bitfields
  • Many compilers limit the maximum number of bits
    in the bit field to the size of an integer which
    may be either 16-bit or 32-bit varieties.
  • Some bit field members are stored left to right
    others are stored right to left in memory.
  • If bit fields too large, next bit field may be
    stored consecutively in memory (overlapping the
    boundary between memory locations) or in the next
    word of memory.
  • If portability of code is a premium you can use
    bit shifting and masking to achieve the same
    results but not as easy to express or read. For
    example
  • unsigned int disk_reg (unsigned int )
    DISK_REGISTER_MEMORY / see if disk error
    occured / disk_error_occured (disk_reg
    0x40000000) gtgt 31

46
Typecasting
  • C is one of the few languages to allow coercion,
    that is forcing one variable of one type to be
    another type. C allows this using the cast
    operator (). So int integernumber
  • float floatnumber9.87  
  • integernumber(int)floatnumber
  • assigns 9 (the fractional part is thrown away) to
    integernumber.
  • And
  • int integernumber10
  • float floatnumber  
  • floatnumber(float)integernumber
  • assigns 10.0 to floatnumber.

47
Typecasting
  • Coercion can be used with any of the simple data
    types including char, so
  • int integernumber
  • char letter'A'  
  • integernumber(int)letter
  • assigns 65 (the ASCII code for A') to
    integernumber.
  • Some typecasting is done automatically -- this is
    mainly with integer compatibility.
  • A good rule to follow is If in doubt cast.
  • Another use is the make sure division behaves as
    requested
  • If we have two integers internumber and
    anotherint and we want the answer to be a float
    then
  • e.g.  floatnumber  (float) internumber /
    (float) anotherint ensures floating point
    division.

48
Preprocessor and Macros
  • Preprocessor includes, substitutes and selects
    text to form finished source code prior to actual
    compile
  • include used to copy in statements from other
    files, usually header files with .h extension
  • define used to define macros
  • simple substitution
  • function-like substitution with arguments
  • undef used to remove previous definition
  • Conditional commands used to selectively include
    or exclude statements
  • if, elif, else, endif
  • ifdef and ifndef test if a name is defined
  • defined() operator test if a name is defined
  • Predefined macros
  • __FILE__Source file name
  • __LINE__Current source line number
  • __DATE__Date compiled
  • __TIME__Time compiled
  • __TIMESTAMP__Compile date/time

49
Preprocessor and Macros
  • include statement
  • include copies code from external files
  • Files copied generally have .h file extension and
    considered "header file"
  • Usually included at beginning of source module
  • May be nested - included file may contain
    include
  • Use of brackets or quotes determines where
    compiler searches for the included file
  • include "stuff2.h"
  • If file name is in quotes, looks first in the
    same location as the module with the include
    statement
  • include ltstuff2.hgt
  • If file name is in brackets, searches according
    to an implementation-defined rule.

50
Preprocessor and Macros
  • define statementWe already saw how define can
    be used to define a simple substitution text for
    a symbol.
  • Format
  • define identifier replacment-text
  • define PI 3.14159
  • define NUM_ROW (sizeof(ax)/sizeof(ax))
  • define LOG_FILE "hacmp.log"
  • Definition can also be function-like, with
    arguments
  • define identifier(arg1,arg2) repl-text
  • When macro is invoked, argument tokens appearing
    in the macro replacement text are replaced with
    the text for that argument in the macro
    invocation.

51
Preprocessor and Macros
  • if directiveif is followed by a intger
    constant expression.
  • If the expression is not zero, the statement(s)
    following the if are compiled, otherwise they
    are ignored.
  • if statements are bounded by a matching endif,
    else or elif
  • Macros, if any, are expanded, and any undefined
    tokens are replaced with 0 before the constant
    expression is evaluated
  • Relational operators and integer operators may be
    used
  • Expression examples
  • if 1
  • if 0
  • if ABE 3
  • if ZOO lt 12
  • if ZIP 'g'
  • if (ABE 2 - 3 ZIP) gt (ZIP - 2)
  • In most uses, expression is simple relational,
    often equality test
  • if SPARKY '7'

52
Preprocessor and Macros
  • else directiveelse marks the beginning of
    statement(s) to be compiled if the preceding if
    or elif expression is zero (false)
  • Statements following else are bounded by
    matching endif
  • Examples if OS 'A' system( "clear" ) else
    system( "cls" ) endif
  • elif directiveelif adds an else-if branch to a
    previous if
  • A series of elif's provides a case-select type
    of structure
  • Statement(s) following the elif are compiled if
    the expression is not zero, ignored otherwise
  • Expression is evaluated just like for if
  • Examples
  • if TST 1 z fn1( y )
  • elif TST 2 z fn2( y, x )
  • elif TST 3 z fn3( y, z, w )
  • endif ...
  • if ZIP 'g' rc gzip( fn )
  • elif ZIP 'q' rc qzip( fn )
  • else rc zip( fn )
  • endif

53
Preprocessor and Macros
  • Conditonal compilationThe following preprocessor
    directives are used for conditional compilation.
    Conditional compilation allows statements to be
    included or omitted based on conditions at
    compile time. if else elif endif ifdef
    ifndef
  • In the following example, the printf statements
    are compiled when the symbol DEBUG is defined,
    but not compiled otherwise
  • / remove to suppress debug printf's/
  • define DEBUG
  • ...
  • x ....
  • ifdef DEBUG
  • printf( "xd\n" )
  • endif
  • ...
  • y ....
  • ifdef DEBUG
  • printf( "yd\n" )
  • endif ...

54
Pointers
  • Pointers provide an indirect method of accessing
    variables.
  • You may be wondering, what is the point of this
    (no pun intended)?
  • Why don't I just make all variables without the
    use of pointers?
  • It's because sometimes you can't.
  • What if you needed an array of ints, but didn't
    know the size of the array before hand?
  • What if you needed a string, but it grew
    dynamically as the program ran?
  • They are all solved through the use of pointers.
    Pointers are also essential in creating larger
    custom data structures, such as linked lists.
  • A pointer when declared is just a reference.
    DECLARING A POINTER DOES NOT CREATE ANY SPACE FOR
    THE POINTER TO POINT TO. We will tackle this
    dynamic memory allocation issue later.
  • A pointer is a reference to an area of memory in
    the heap. The heap is a dynamically allocated
    area of memory when the program runs.

55
Pointers
  • Pointers are declared by using the infront of
    the variable identifier.
  • For example
  • int ip
  • float fp NULL
  • char a
  • This declares a pointer, ip, to an integer.
  • Let's say we want ip to point to an integer.
  • The second line declares a pointer to a float,
    but initializes the pointer to point to the NULL
    pointer. The NULL pointer points to a place in
    memory that cannot be accessed. NULL is useful
    when checking for error conditions and many
    functions return NULL if they fail.
  • Third line declares pointer to a char.
  • int x 5
  • int ip
  • ip x
  • The operator is to specify the address-of x.
    Thus, the pointer, ip is pointing to x by
    assigning the address of x.
  • The dereferences the pointer to the value.
  • So, printf("d d\n", x, ip) would print 5 5 to
    the screen.

56
Pointers
  • What is the output of this program?
  • main()
  • int i 54
  • float a 3.14
  • char ii, aa
  • ii i
  • aa a
  • printf(\nAddress contained in ii u, ii)
  • printf(\nAddress contained in ii u, ii)
  • printf(\nValue at the address contained in ii
    d, ii)
  • printf(\nValue at the address contained in ii
    d, aa)

a
i
Binary equivalent of 54
Binary equivalent of 3.14
7006
7008
7009
2008
2009
7007
57
Pointers
  • Output
  • ii and aa are declared as char pointers. Still
    the statements ii i and aa a work.
  • The addresses 2008 and 7006 get stored in ii and
    cc which are printed through the first two
    printf()s.
  • However the program falters at the next two
    printf()s.
  • This is so since ii is a character pointer ii
    gives value at address 2008 and not the one
    present in 2008 and 2009.
  • Similarly aa gives the value at 7006 and not the
    one contained in 7006, 7007, 7008 and 7009.
  • Moral is if you wish to access an integer value
    stored in a variable using its address its
    necessary that the address be stored in an
    integer pointer. Likewise if you wish to access a
    float value stored in a variable using its
    address its necessary to store the address in a
    float pointer.

58
Pointers
  • Functions Returning Pointers
  • The way functions return an int, a float, a
    double or any other data type, it can even return
    a pointer.
  • However, to make a function return a pointer it
    has to be explicitly mentioned in the calling
    function as well as in the function declaration.
  • Example
  • main()
  • int p
  • int fun()
  • pfun()
  • printf(\nu,p)
  • int fun()
  • int i20
  • return (i)

59
Pointers
  • Pointer Arithmetic
  • C is one of the few languages that allows pointer
    arithmetic.
  • In other words, you actually move the pointer
    reference by an arithmetic operation.
  • For example
  • int x 5,
  • ip x
  • ip
  • On a typical 32-bit machine,
  • ip would be pointing to 5 after initialization.
  • But ip increments the pointer 32-bits or
    4-bytes.
  • So whatever was in the next 4-bytes, ip would be
    pointing at it.
  • Pointer arithmetic is very useful when dealing
    with arrays, because arrays and pointers share a
    special relationship in C.

60
Pointers
  • Pointer Arithmetic(Contd)
  • What is the output?
  • main()
  • float fun(float )
  • float p23.5, q
  • q p
  • printf(\nq before call u,q)
  • q fun(p)
  • printf(\nq after call u,q)
  • float fun(float r)
  • r r1
  • return(r)

61
Pointers
  • Pointer Arithmetic(Contd)
  • Output
  • q before call 5498
  • q after call 5502
  • In main(), q has been declared as a float
    pointer. It means q is a variable capable of
    holding the address of a float. Through q p the
    address of p, a float value is stored in q and
    then printed out through the printf(). This is
    the value before fun() is called. When fun() is
    called the address of p is sent to it and is
    collected in r. At this juncture r contains 5498.
    When r is incremented it would become 5502. r is
    a float pointer and on incrementing by 1 it would
    point to the next float which would be present 4
    bytes hence, since every float is 4 bytes long.
    The return statement then return this address
    5502 back to main()

62
Pointers
  • Pointer Arithmetic(Contd)
  • Pointers can be incremented and can be
    decremented as well, to point to earlier
    locations. Thus the following operations can be
    performed
  • Addition of a number to a pointer. For example,
  • int i4,j,k
  • ji
  • jj1
  • jj9
  • kj3
  • Subtraction of a number from a pointer. For
    example,
  • int i4,j,k
  • ji
  • jj-2
  • jj-5
  • kj-6
  • A word of caution Do not attempt the following
    operations on pointers.. They never work out
  • Addition of two pointers
  • Multiplying a pointer with a number
  • Dividing a pointer with a number

63
Pointers
  • What is the output?
  • main()
  • int a10,20,30,40,50
  • int j
  • for (j0jlt5j)
  • printf(\nd,a)
  • a

64
Pointers
  • Output
  • Error messageLvalue required in function main
  • Whenever we mention the name of the array, we get
    its base address. Therefore for the first time
    through the loop, the printf() should print the
    value at its base address. There is no problem up
    to this. The problem lies in the next statement,
    a. Since C does not perform bounds checking on
    an array, the only thing it remembers about an
    array once declared is its base address. And a
    attempts to change this base address, which C
    wont allow because if it does so, it would be
    unable to remember the beginning of the array.
    Anything which can change in compilers language
    is called lvalue. Since value of a cannot be
    changed through , it flashes the error saying
    L value required so that operator can change
    it.

65
Pointers
  • What is the output?
  • main()
  • float a13.24,1.5,1.5,5.4,3.5
  • Float j,k
  • j a
  • k a 4
  • j j 2
  • k k / 2
  • printf(\nf f,j,k)

66
Pointers
  • Output
  • Error message Illegal use of pointer in function
    main
  • j and k have been declared as pointer variables,
    which would contain the addresses of floats. In
    other words, j and k are the pointers. To begin
    with, the base address of the array a is stored
    in j. The next statement is perfectly acceptable
    the address of the 4th float from the base
    address is stored in k. The next two statements
    are erroneous. This is because the only
    operations that can be performed on pointers are
    addition and subtraction. Multiplication and
    division of a pointer is not allowed. Hence the
    error message.

67
Pointers
  • Pointers to structs
  • Sometimes it is useful to assign pointers to
    structures.
  • Declaring pointers to structures is basically the
    same as declaring a normal pointer
  • struct student student_a
  • But how do we dereference the pointer to the
    struct and its fields? You can do it in one of
    two ways, the first way is
  • printf("s\n", (student_a).SSN)
  • This would get the SSN in student_a. Messy and
    the readability is horrible! Is there a better
    way? Of course, programmers are lazy! )
  • To dereference, you can use the infix operator
    -gt. The above example using the new operator
  • printf("s\n", student_a-gtSSN)
  • If we malloc'd space for the structure for
    student_a could we start assigning things to
    pointer fields inside the structure? No. You must
    malloc space for each individual pointer within
    the structure that is being pointed to.

68
Pointers
  • Common error while using pointers
  • Using an uninitialized pointer.
  • Remember, declaring a pointer variable simply
    allocates a cell that can hold a pointer - it
    does not place a value in the cell. So, for
    example, a code fragment like
  • int iptr
  • iptr 2
  • . . .
  • will attempt to place the value, 2, in the cell
    pointed to by iptr however, iptr has not been
    initialized, so some garbage value will be used
    as the address of there to place the value. On
    some systems this may result in an attempt to
    access an illegal address, and a memory
    violation. Avoid this error by remembering to
    initialize all pointer variables before they are
    used.

69
Pointers
  • Common error while using pointers(Contd)
  • Instead of using a pointer to an object, a
    pointer to a pointer is used.
  • Consider a function, read_int(). It reads an
    integer and stores it where its argument points.
    The correct version is
  • void read_int(int pn)
  • scanf("d", pn)
  • pn is a pointer to the object where the integer
    is to be stored. When passing the argument to
    scanf(), we pass the pointer, pn, NOT pn.

70
Pointers
  • Common error while using pointers(Contd)
  • Confusion between the address of operator and the
    dereference operator.
  • ...
  • calling_func(...)
  • int x
  • called_func(x) / should be x / ...
  • ...
  • called_func(int px) / should be px /
  • ...
  • A useful mnemonic aid is that the address of''
    operator is the and'' symbol, --- both start
    with letter, a.

71
Function Pointers
  • Function Pointers are pointers, i.e. variables,
    which point to the address of a function
  • Ex int (pt2Function) (float, char, char)
  • //assign an address to the function pointer
  • int DoIt (float a, char b, char c)
  • printf("DoIt\n)
  • return abc
  • int DoMore(float a, char b, char c)
  • printf("DoMore\n"
  • return a-bc
  • pt2Function DoMore // assignment
  • pt2Function DoIt // alternative using address
    operator

72
Function Pointers
  • Comparing Function PointersThe
    comparison-operator () is used for comparing
    function
  • Ex // comparing function pointers
  • if(pt2Function DoIt)
  • Printf("pointer points to DoIt\n)"
  • Calling a Function using a Function Pointer
  • There are two alternatives to call a function
    using a function pointer
  • Use the name of the function pointer instead of
    the name of the function.
  • Explicitly dereference it.
  • Ex // calling a function using a function
    pointer
  • int result1 pt2Function (12, 'a', 'b')
  • int result2 (pt2Function) (12, 'a', 'b')

73
Function Pointers
  • Returning a Function PointerA function pointer
    can be a function's return value.
  • float (GetPtr1(const char opCode))(float, float)
  • if(opCode '')
  • return Plus
  • if(opCode '-')
  • return Minus
  • // using a typedef
  • typedef float(pt2Func)(float, float)
  • pt2Func GetPtr2(const char opCode)
  • if(opCode '')
  • return Plus
  • if(opCode '-')
  • return Minus

74
Function Pointers
  • // execute example code
  • void Return_A_Function_Pointer()
  • Printf( "Executing 'Return_A_Function_Pointer\n')
  • float (pt2Function)(float, float) // define a
    function pointer
  • pt2FunctionGetPtr1('') // get function pointer
    from function 'GetPtr1
  • Printf(pt2Function(2, 4) \n) // call function
    using the pointer
  • Printf(pt2FunctionGetPtr2('-') \n) // get
    function pointer from function 'GetPtr2
  • Printf(pt2Function(2, 4)\n) // call function
    using the pointer
  • Function pointers are usually used
  • In writing memory resident programs
  • In writing viruses or vaccines to remove the
    viruses

75
Function Pointers
  • Arrays of Function Pointers// 2.8 How to Use
    Arrays of Function Pointers typedef int
    (pt2Function)(float, char, char)
  • // illustrate how to work with an array of
    function pointers
  • Void Array_Of_Function_Pointers()
  • printf("Executing Array_Of_Function_Pointers\n)
  • // ltfuncArrgt is an array with 10 pointers to
    functions which return an int // and take a float
    and two char
  • pt2Function funcArr10 // assign the function's
    address - 'DoIt' and 'DoMore' are suitable
    functions // like defined above in 2.1-4
  • funcArr0 DoIt
  • funcArr1 DoMore / more assignments /
  • // calling a function using an index to address
    the function pointer
  • printf(funcArr1(12, 'a', 'b')\n)
  • printf(funcArr0(12, 'a', 'b')\n)

76
Libraries
  • A " library'' is simply a file containing
    compiled code (and data) that is to be
    incorporated later into a program
  • A library is a file containing several object
    files, that can be used as a single entity in a
    linking phase of a program.
  • Libraries allow programs to be more modular,
    faster to recompile, and easier to update.
  • Normally the library is indexed, so it is easy to
    find symbols (functions, variables and so on)
Write a Comment
User Comments (0)
About PowerShow.com