C_lang_Ref_Raja

download C_lang_Ref_Raja

of 39

Transcript of C_lang_Ref_Raja

  • 8/14/2019 C_lang_Ref_Raja

    1/39

    C_Lang_Ref Raja 1

    C Language Reference

  • 8/14/2019 C_lang_Ref_Raja

    2/39

    C_Lang_Ref Raja 2

    C IS A STRUCTURED LANGUAGE ............. .............. ............... .............. .............. .............. .............. .........3

    HOW A DECLARATION IS FORMED: ....................................................................................................3

    POINTER .............. .............. .............. ............... .............. .............. .............. .............. .............. ........... ...... ...... ..5

    STRUCTURE ............. .............. .............. .............. .............. .............. ............... .............. .............. .............. ......6

    MACROS .............. .............. ............... .............. .............. .............. .............. ............... .............. .............. ...........6LIBRARY AND LINKING: ............. .............. .............. .............. .............. ............... .............. .............. ..........6

    PROCESS MEMORY LAYOUT ............. .............. .............. ............... .............. .............. ........... ..... ...... ...... ..6

    TYPE QUALIFIERS ............. .............. .............. .............. ............... .............. .............. .............. .............. ...... ..9

    CONST............................................................................................................................................................ 9

    VOLATILE...................................................................................................................................................... 10

    Volatile Article ......................................................................................................................................11

    STORAGE CLASS SPECIFIERS: ............................................................................................................15

    EXTERN........................................................................................................................................................15STATIC.......................................................................................................................................................... 16

    Static Local variables ...........................................................................................................................16Static Global Variable ...........................................................................................................................16

    REGISTER..................................................................................................................................................... 17

    VARIABLE INITIALIZATION................................................................................................................................ 17

    CONSTANTS .............. .............. .............. .............. ............... .............. .............. .............. .............. ...... ...... .....17

    OPERATORS ............ ............... .............. .............. .............. .............. .............. ............... .............. ............ ..... .17

    ASSIGNMENT.................................................................................................................................................. 18

    INCREMENTAND DECREMENT OPERATORS.......................................................................................................... 18

    RELATIONAL AND LOGICAL OPERATORS .............. .............. .............. ............... ........... ..... ..... ...... ...18

    THE COMPILE-TIME OPERATORSIZEOF.............................................................................................................. 19

    BITWISE OPERATORS....................................................................................................................................... 19

    OPERATOR PRECEDENCE..................................................................................................................................19SOMEOFTHE OPERATORS HAVETHE WRONG PRECEDENCE.................................................................................. 20

    ASSOCIATIVITY............................................................................................................................................... 21

    TYPEDEF .............. .............. .............. .............. .............. ............... .............. .............. .............. .............. ........ .21

    FUNCTION POINTERS ............. .............. .............. .............. ............... .............. .............. .............. ............. .22

    THE CONST FUNCTION ATTRIBUTE ............. .............. .............. .............. ............... .............. .......... .....22

    SORTING AND SEARCHING ALGORITHMS ............. ............... .............. .............. .............. .............. ...22

    COMPARISONSORT: ................................................................................................................................ ...... ...22

    SORTING ALGORITHMS: ...................................................................................................................................23

    COMPARISION: ................................................................................................................................................23

    ORDERSOFCOMMONFUNCTIONS....................................................................................................................... 24

    C QUESTIONS: .............. .............. .............. .............. .............. ............... .............. .............. .............. ......... ....25

    THE PRECEDENCE RULE .............. .............. ............... .............. .............. .............. .............. ....... ..... ..... ...27

    A 'C' TEST: THE 0X10 BEST QUESTIONS FOR WOULD-BE EMBEDDED PROGRAMMERS . 30

    REFERENCE: .............. .............. .............. ............... .............. .............. .............. .............. ........... ..... ..... ..... ...39

  • 8/14/2019 C_lang_Ref_Raja

    3/39

    C_Lang_Ref Raja 3

    C is a Structured Language

    How a declaration is formed:

    An important building block is a declaratorthe heart of any declaration; roughly, a declaratoris the identifier and any pointers, function brackets, or array indica-tions that go along with it

  • 8/14/2019 C_lang_Ref_Raja

    4/39

    C_Lang_Ref Raja 4

  • 8/14/2019 C_lang_Ref_Raja

    5/39

    C_Lang_Ref Raja 5

    Pointer

    Pointer is an address variable which contains address of another variable.

    Pointer operators are * and &.

    int pointer contains address of int quantity, float contains float quantity, same holds

    good for each data type even for user defined data types.

    Maximum size of pointer is 2 bytes.

  • 8/14/2019 C_lang_Ref_Raja

    6/39

    C_Lang_Ref Raja 6

    StructureA structure is a collection of one or more variables, possibly of different data types, groupedtogether under a single name for convenient handling.

    Macros

    Macros are preprocessor directives. They get replaced in source code before compilation.

    Advantages:

    We can replace any valid C statement or condition in user own words. We can do File

    inclusion also. We can do conditional compilation. We can pass arguments also inMacros. They can be used anywhere inside the program.

    Disadvantages:

    Macro will replace macro template with its macro expansion without checking any

    error. If there r number of occurrence of macros then it will increase the size ofprogram.

    Library and Linking:

    Process Memory Layout

    A running program is called a process and when a program is run, its executableimage is loaded into memory area that normally called a process address space in anorganized manner.

    This is a physical memory space and do not confuse yourself with the virtual address

    space .

    Process address space is organized into three memory areas, called segments: thetext segment, stack segment, and data segment (bss and data) and can beillustrated below.

    The text segment (also called a code segment) is where the compiled code of theprogram itself resides.

    In the disk file (object files) the segments were called sections.

  • 8/14/2019 C_lang_Ref_Raja

    7/39

    C_Lang_Ref Raja 7

  • 8/14/2019 C_lang_Ref_Raja

    8/39

    C_Lang_Ref Raja 8

  • 8/14/2019 C_lang_Ref_Raja

    9/39

    C_Lang_Ref Raja 9

    Type Qualifiers

    const

    volatile

    restrict

    Const

  • 8/14/2019 C_lang_Ref_Raja

    10/39

    C_Lang_Ref Raja 10

    Variables of type const may not be changed by your program. The compiler is free to placevariables of this type into read-only memory (ROM). Many functions in the standard library useconst in their parameter declarations.You can also use const to verify that your program does not modify a variable.

    Remember, a variable of type constcan be modified by something outside your

    program. For example, a hardware device may set its value. However, by declaring avariable as const, you can prove that any changes to that variable occur because ofexternal events.

    where do, const variables (i.e constants or literals) get memory , is there isseparate area for them or they are allocated in the data region only.

    This is very much system-specific. Const variables can be allocated in three different places: inROM, in RAM or in code ROM. On a RAM-based system such as a PC, the ROM is just anothersegment of the RAM, as there is no physical ROM.

    - The variable ends up in ROM if you declare it as a global constant.- The variable ends up in RAM if you declare it as a local constant or a parameter to a function.- The variable ends up in code ROM if the compiler optimizes the expression where the

    variable is used. It can also end up in ROM if you use numeric constants or strings:

    char x = 5;/* 5 is allocated in code ROM */char* ptr = abc;/* abc is allocated in code ROM */

    Constants allocated in ROM or RAM can be viewed while debugging, as opposed to constants incode ROM.

    ROM is the preferred memory type in most cases. First of all, it isnt volatile, so constants

    placed in ROM on ROM-based systems are much safer than constants placed in RAM. In mostcases, constants in ROM can also be placed at fixed locations; although the method of how aconstant is placed at a specific address in ROM is not specified by ISO C. Constants in RAMusually end up on the stack, and are allocated in runtime.

    Volatile

    The modifier volatile tells the compiler that a variable's value may be changed in ways notexplicitly specified by the program. For example, a global variable's address may be passed tothe operating system's clock routine and used to hold the system time. In this situation, thecontents of the variable are altered without any explicit assignment statements in theprogram. This is important because most C compilers automatically optimize certainexpressions by assuming that a variable's content is unchanging if it does not occur on the leftside of an assignment statement; thus, it might not be reexamined each time it is referenced.

    Also, some compilers change the order of evaluation of an expression during the compilationprocess. The volatile modifier prevents these changes.

    You can use const and volatile together. For example, if 0x30 is assumed to be thevalue of a port that is changed by external conditions only, the following declarationwould prevent any possibility of accidental side effects:

    const volatile char *port = (const volatile char *) 0x30;

  • 8/14/2019 C_lang_Ref_Raja

    11/39

    C_Lang_Ref Raja 11

    Volatile Article

    Have you experienced any of the following in your C or C++ embedded code?

    Code that works fine--until you enable compiler optimizations Code that works fine--until interrupts are enabled

    Flaky hardware drivers RTOS tasks that work fine in isolation--until some other task is spawned

    If you answered yes to any of the above, it's likely that you didn't use the C keyword volatile.

    C's volatile keyword is a qualifier that is applied to a variable when it is declared. It tells the

    compiler that the value of the variable may change at any time--without any action beingtaken by the code the compiler finds nearby.

    volatile keyword syntax

    To declare a variable volatile, include the keyword volatile before or after the data type in thevariable definition. For instance both of these declarations will declare foo to be a volatile

    integer:

    volatile int foo;

    int volatile foo;

    Now, it turns out that pointers to volatile variables are very common, especially with memory-mapped I/O registers. Both of these declarations declare pReg to be a pointer to a volatileunsigned 8-bit integer:

    volatile uint8_t * pReg;

    uint8_t volatile * pReg;

    Volatile pointers to non-volatile data are very rare (I think I've used them once), but I'd bettergo ahead and give you the syntax:

    int * volatile p;

    And just for completeness, if you really must have a volatile pointer to a volatile variable,you'd write:

    int volatile * volatile p;

    Incidentally, for a great explanation of why you have a choice of where to place volatile and

    why you should place it after the data type (for example, int volatile * foo), read Dan Sak'scolumn "Top-Level cv-Qualifiers in Function Parameters" (Embedded Systems Programming,

    February 2000, p. 63).

    Finally, if you apply volatile to a struct or union, the entire contents of the struct/union arevolatile. If you don't want this behavior, you can apply the volatile qualifier to the individualmembers of the struct/union.

    Proper use of volatile

  • 8/14/2019 C_lang_Ref_Raja

    12/39

    C_Lang_Ref Raja 12

    A variable should be declared volatile whenever its value could change unexpectedly. Inpractice, only three types of variables could change:

    1. Memory-mapped peripheral registers

    2. Global variables modified by an interrupt service routine

    3. Global variables accessed by multiple tasks within a multi-threaded application

    We'll talk about each of these cases in the sections that follow.

    Peripheral registers

    Embedded systems contain real hardware, usually with sophisticated peripherals. Theseperipherals contain registers whose values may change asynchronously to the program flow.As a very simple example, consider an 8-bit status register that is memory mapped at address0x1234. It is required that you poll the status register until it becomes non-zero. The naiveand incorrect implementation is as follows:

    uint8_t * pReg = (uint8_t *) 0x1234;

    // Wait for register to become non-zero

    while (*pReg == 0) { } // Do something else

    This will almost certainly fail as soon as you turn compiler optimization on, since the compilerwill generate assembly language that looks something like this:

    mov ptr, #0x1234 mov a, @ptr

    loop:

    bz loop

    The rationale of the optimizer is quite simple: having already read the variable's value into theaccumulator (on the second line of assembly), there is no need to reread it, since the valuewill always be the same. Thus, in the third line, we end up with an infinite loop. To force thecompiler to do what we want, we modify the declaration to:

    uint8_t volatile * pReg = (uint8_t volatile *) 0x1234;

    The assembly language now looks like this:

    mov ptr, #0x1234

    loop:

  • 8/14/2019 C_lang_Ref_Raja

    13/39

    C_Lang_Ref Raja 13

    mov a, @ptr

    bz loop

    The desired behavior is achieved.

    Subtler problems tend to arise with registers that have special properties. For instance, a lot ofperipherals contain registers that are cleared simply by reading them. Extra (or fewer) readsthan you are intending can cause quite unexpected results in these cases.

    Interrupt service routines

    Interrupt service routines often set variables that are tested in mainline code. For example, aserial port interrupt may test each received character to see if it is an ETX character(presumably signifying the end of a message). If the character is an ETX, the ISR might set aglobal flag. An incorrect implementation of this might be:

    int etx_rcvd = FALSE;

    void main()

    {

    ...

    while (!ext_rcvd)

    {

    // Wait

    }

    ...

    }

    interrupt void rx_isr(void)

    {

    ...

    if (ETX == rx_char)

    {

    etx_rcvd = TRUE;

  • 8/14/2019 C_lang_Ref_Raja

    14/39

    C_Lang_Ref Raja 14

    }

    ...

    }

    With compiler optimization turned off, this code might work. However, any half decentoptimizer will "break" the code. The problem is that the compiler has no idea that etx_rcvd canbe changed within an ISR. As far as the compiler is concerned, the expression !ext_rcvd isalways true, and, therefore, you can never exit the while loop. Consequently, all the code afterthe while loop may simply be removed by the optimizer. If you are lucky, your compiler willwarn you about this. If you are unlucky (or you haven't yet learned to take compiler warningsseriously), your code will fail miserably. Naturally, the blame will be placed on a "lousyoptimizer."

    The solution is to declare the variable etx_rcvd to be volatile. Then all of your problems (well,some of them anyway) will disappear.

    Multi-threaded applications

    Despite the presence of queues, pipes, and other scheduler-aware communicationsmechanisms in real-time operating systems, it is still fairly common for two tasks to exchangeinformation via a shared memory location (that is, a global). Even as you add a preemptivescheduler to your code, your compiler has no idea what a context switch is or when one mightoccur. Thus, another task modifying a shared global is conceptually identical to the problem ofinterrupt service routines discussed previously. So all shared global variables should bedeclared volatile. For example, this is asking for trouble:

    int cntr;

    void task1(void)

    {

    cntr = 0;

    while (cntr == 0)

    {

    sleep(1);

    }

    ...

    }

  • 8/14/2019 C_lang_Ref_Raja

    15/39

    C_Lang_Ref Raja 15

    void task2(void)

    {

    ...

    cntr++;

    sleep(10);

    ...

    }

    This code will likely fail once the compiler's optimizer is enabled. Declaring cntr to be volatile isthe proper way to solve the problem.

    Final thoughts

    Some compilers allow you to implicitly declare all variables as volatile. Resist this temptation,since it is essentially a substitute for thought. It also leads to potentially less efficient code.

    Also, resist the temptation to blame the optimizer or turn it off. Modern optimizers are so goodthat I cannot remember the last time I came across an optimization bug. In contrast, I comeacross failures by programmers to use volatile with depressing frequency.

    If you are given a piece of flaky code to "fix," perform a grep for volatile. If grep comes upempty, the examples given here are probably good places to start looking for problems.

    Storage Class Specifiers:

    C supports four storage class specifiers:externstaticregisterauto

    These specifiers tell the compiler how to store the subsequent variable. The general form of avariable declaration that uses one is shown here:

    storage_specifier type var_name;

    Extern

    C defines three categories of linkage:External-> functions and global variables have external linkage. This means they are

    available to all files that constitute a program. internal -> File scope objects declared as static have internal linkage. These are known

    only within the file in which they are declared. None -> variables have no linkage and are therefore known only within their own block.

  • 8/14/2019 C_lang_Ref_Raja

    16/39

    C_Lang_Ref Raja 16

    A declaration declares the name and type of an object.

    A definition causes storage to be allocated for the object.

    The same object may have many declarations, but there can be only one

    definition.

    In most cases, variable declarations are also definitions. However, by preceding a variablename with the extern specifier, you can declare a variable without defining it. Thus, when youneed to refer to a variable that is defined in another part of your program, you can declarethat variable using extern.

    extern can also be applied to a function declaration, but doing so is redundant.

    Static

    Static variable:Variables declared as static are permanent variables within their own function or file.

    They are stored in memory. Default initial value is zero.

    Their scope is local to the block in which the variable is defined &

    Value of the variable persists between different function calls.

    Avoid using static unless we need it. Because their values are kept in memory when

    the variables are not active.

    Static Local variables

    Ifstatic variables were not allowed, globals would have to be used, opening the door topossible side effects. An example of a function that benefits from a static local variable is anumber -series generator that produces a new value based on the previous one. You could usea global variable to hold this value. However, each time the function is used in a program, you

    would have to declare that global variable and make sure it did not conflict with any otherglobal variables already in place. The better solution is it declares the variable that holds thegenerated number to be static.

    Static Global Variable

    Applying the specifier static to a global variable instructs the compiler to create a globalvariable known only to the file in which it is declared. Thus, a static global variable has internallinkage (as described under the extern statement). This means those even though thevariable is global, routines in other files have no knowledge of it and cannot alter its contentsdirectly, keeping it free from side effects. For the few situations where a local static cannot dothe job, you can create a small file that contains only the functions that need the global staticvariable, separately compile that file, and use it without fear of side effects.

    To review:

    The names of local static variables are known only to the block of code in which they aredeclared; the names of global static variables are known only to the file in which they reside.In fact, you can even declare and use another variable with same namein your program (inanother file, of course). In essence, the static modifier permits variables that are known onlyto the functions that need them, without unwanted side effects.

  • 8/14/2019 C_lang_Ref_Raja

    17/39

    C_Lang_Ref Raja 17

    By using static variables, you can hide portions of your program from other portions. This canbe a tremendous advantage when you are trying to manage a very large and complexprogram.

    Register

    Originally, the register specifier requested that the compiler keep the value of a variable in aregister of the CPU rather than in memory, where normal variables are stored. This meant thatoperations on a register variable could occur much faster than on a normal variable becausethe register variable was actually held in the CPU and did not require a memory access todetermine or modify its value.

    In fact, it is technically permissible for a compiler to ignore the register specifier altogetherand treat variables modified by it as if they were ''normal" variables, but this is seldom done inpractice.

    You can only apply the register specifier to local variables and to the formalparameters in a function. Global register variables are not allowed.

    register variables are optimized for speed makes them ideal for control of or usein loops.

    We can declare any number of variables as being of type register, but not all willreceive the same access speed optimization.

    The number ofregister variables optimized for speed allowed within any one codeblock is determined by both the environment and the specific implementation of C.

    In C, you cannot obtain the address of a register variable by using the &operatorthis makes sense because a register variable may be stored in a register of the CPU,which is not usually addressable.

    Variable Initialization

    Global and static local variables are initialized only at the start of the program.

    Local variables (excluding static local variables) are initialized each time the block inwhich they are declared is entered.

    Local variables that are not initialized have unknown values before the first assignment

    is made to them.

    Uninitialized global and static local variables are automatically set to zero.

    Constants

    Character constants are enclosed between single quotes. For example, 'a' and '%' are bothcharacter constants. C defines both multibyte characters, which consist of one or more bytes,and wide characters (which are usually 16 bits long). Multibyte and wide characters are usedprimarily to represent languages that have large character sets. To specify a multibytecharacter, enclose the characters within single quotes, for example, 'xy'. To specify a widecharacter constant, precede the character with an L.

    Operators

  • 8/14/2019 C_lang_Ref_Raja

    18/39

    C_Lang_Ref Raja 18

    There are four main classes of operators: arithmetic, relational, logical, and bitwise.

    Assignment

    Frequently in literature on C and in compiler error messages you will see these two terms:lvalue and rvalue. Simply put, an lvalueis an object. If that object can occur on the left sideof an assignment statement, it is called a modifiable lvalue. Thus, for all practical purposes, amodifiable lvalue means ''variable." The term rvaluerefers to expressions on the right side ofan assignment and simply means the value of an expression.

    Increment and Decrement Operators

    Operators on the same level of precedence are evaluated by the compiler from left to right.

    Relational and logical Operators

    In the term relational operator, relationalrefers to the relationships that values can have withone another. In the term logical operator, logicalrefers to the ways these relationships can beconnected. Both the relational and logical operators are lower in precedence than thearithmetic operators.

  • 8/14/2019 C_lang_Ref_Raja

    19/39

    C_Lang_Ref Raja 19

    The Compile-Time Operator sizeof

    sizeofis a unary compile-time operator that returns the length, in bytes, of the variable or

    parenthesized type specifier that it precedes.

    Bitwise Operators

    We cannot use bitwise operations on float , double, long double, void , or other more complextypes.

    Uses:

    Bitwise operations(&, |, ^) most often find application in device drivers such asmodem programs, disk file routines, and printer routines because the bitwiseoperations can be used to mask off certain bits, such as parity. (The parity bit confirmsthat the rest of the bits in the byte are unchanged. It is often the high-order bit ineach byte.)

    Bit-shift operations() can be very useful when you are decoding input from anexternal device, such as a D/A converter, and reading status information. The bitwiseshift operators can also quickly multiply and divide integers.

    A shift right effectively divides a number by 2 and a shift left multiplies it by 2.

    The bitwise operators(~) are often used in cipher routines. If you want to make a disk

    file appear unreadable, perform some bitwise manipulations.

    Operator Precedence

  • 8/14/2019 C_lang_Ref_Raja

    20/39

    C_Lang_Ref Raja 20

    Some of the Operators Have the Wrong Precedence

  • 8/14/2019 C_lang_Ref_Raja

    21/39

    C_Lang_Ref Raja 21

    Associativity

    The only use of associativity is to disambiguate an expression of two or more equalprecedenceoperators.

    All assignment-operators have right associativity.

    operators with left associativity (such as the bitwise and's and or 's), the operands are

    grouped from left to right.

    TypedefDon't bother with typedefs for structs. All they do is save you writing the word "struct", which

    is a clue that you probably shouldn't be hiding anyway.Use typedefs for: types that combine arrays, structs, pointers, or functions. portable types. When you need a type that's at least (say) 20-bits, make it a typedef.

    Then when you port the code to different platforms, select the right type, short,int, long, making the change in just the typedef, rather than in everydeclaration.

  • 8/14/2019 C_lang_Ref_Raja

    22/39

    C_Lang_Ref Raja 22

    casts. A typedef can provide a simple name for a complicated type cast. E.g.typedef int (*ptr_to_int_fun)(void);char * p;= (ptr_to_int_fun) p;

    Always use a tag in a structure definition, even if it's not needed. It will be later.

    Function PointersFunction Pointers are pointers, i.e. variables, which point to the address of a function.

    Function Pointers provide some extremely interesting, efficient and elegant

    programming techniques. You can use them to replace switch/if-statements, to realizeyour own late-binding or to implement callbacks.

    They are less error prone than normal pointers cause you will never allocate or de-allocate memory with them.

    One aspect in the case of late-binding is runtime: If you call a virtual function, your

    program has got to determine which one has got to be called. It does this using a V-

    Table containing all the possible functions. This costs some time each call and maybeyou can save some time using function pointers instead of virtual functions.

    The const function attribute

    The const function attribute allows you to tell the compiler that the function can safely becalled fewer times than indicated in the source code. The language feature provides you withan explicit way to help the compiler optimize code by indicating that the function does notexamine any values except its arguments and has no effects except for its return value.

    const function attribute syntax>>-__attribute__--((--+-const-----+--))------------------------>Lmain(){int a=6;

    int *x=&a;printf("%d %d %d " , a, ++a, a++);}o/p: 8 8 6

    5. Pointer Definition ... Refer Expert C Programming book for betterunderstanding

    int const *p; const int x;const int *p; p=&xpointer to a constant integer. P can be point to another variable but thevalue of x cant be changed.

    int *const p; int x;Constant pointer to a integer. P cant be point to another integer, butthe value of the integer can be changed.

    Char * const * (*f)();f is a pointer to a function returning pointer to a read onlypointer-to-char

    char * (*c[10])(int **p)C is a array [10] of pointer to a function returning a pointer-to-char

    The Precedence Rule

  • 8/14/2019 C_lang_Ref_Raja

    28/39

    C_Lang_Ref Raja 28

    solving a declaration using the Precedence Rule: char* const *(*next)() ;

    Then put it all together to read:

    "next is a pointer to a function returning a pointer to a const pointer-to-char"

  • 8/14/2019 C_lang_Ref_Raja

    29/39

    C_Lang_Ref Raja 29

    6. Can we return an array from a function, not pointer to an array ?We cant directly return an array from a function. But we can do this by putting thearray in the structure and returning the structure.

    Anyway return array from the function is a very rare case.

    7. Difference between typedef and #define

    You can extend a macro typename with other type specifiers, but not a typedef 'd

    typename.

    #define X int

  • 8/14/2019 C_lang_Ref_Raja

    30/39

    C_Lang_Ref Raja 30

    Unsigned X abc; /*Works fine*/typedef int X;unsigned X abc; /*Illegal*/

    typedef 'd name provides the type for every declarator in a declaration.

    #define X int* X a,b; // a is pointer to a interger and b is just an int

    typedef X int* X a, b; //Both a and b are pointers to an int

    8.

    A 'C' Test: The 0x10 Best Questions for Would-be Embedded Programmers

    Nigel JonesPencils up, everyone. Here's a test to identify potential embedded programmers or

    embedded programmers with potential

    A n obligatory and significant part of the recruitment process for embedded systemsprogrammers seems to be the "C test." Over the years, I have had to both take and prepare

    such tests and, in doing so, have realized that these tests can be informative for both the

    interviewer and interviewee. Furthermore, when given outside the pressure of aninterview situation, these tests can also be quite entertaining.

    From the interviewee's perspective, you can learn a lot about the person who has written

    or administered the test. Is the test designed to show off the writer's knowledge of theminutiae of the ANSI standard rather than to test practical know-how? Does it test

    ludicrous knowledge, such as the ASCII values of certain characters? Are the questions

    heavily slanted towards your knowledge of system calls and memory allocation

    strategies, indicating that the writer may spend his time programming computers insteadof embedded systems? If any of these are true, then I know I would seriously doubt

    whether I want the job in question.

    From the interviewer's perspective, a test can reveal several things about the candidate.Primarily, you can determine the level of the candidate's knowledge of C. However, it's

    also interesting to see how the person responds to questions to which they don't know the

    answers. Do they make intelligent choices backed up with good intuition, or do they justguess? Are they defensive when they are stumped, or do they exhibit a real curiosity

    about the problem and see it as an opportunity to learn something? I find this information

    as useful as their raw performance on the test.With these ideas in mind, I have attempted to construct a test that is heavily slanted

    towards the requirements of embedded systems. This is a lousy test to give to someone

    seeking a job writing compilers! The questions are almost all drawn from situations I

    have encountered over the years. Some of them are tough; however, they should all beinformative.

  • 8/14/2019 C_lang_Ref_Raja

    31/39

    C_Lang_Ref Raja 31

    This test may be given to a wide range of candidates. Most entry-level applicants will do

    poorly on this test, while seasoned veterans should do very well. Points are not assigned

    to each question, as this tends to arbitrarily weight certain questions. However, if youchoose to adapt this test for your own uses, feel free to assign scores.

    Preprocessor

    1. Using the #define statement, how would you declare a manifest constant that returnsthe number of seconds in a year? Disregard leap years in your answer.#define SECONDS_PER_YEAR

    (60 * 60 * 24 * 365)UL

    I'm looking for several things here:

    Basic knowledge of the #define syntax (for example, no semi-colon at the end, the

    need to parenthesize, and so on)

    An understanding that the pre-processor will evaluate constant expressions for

    you. Thus, it is clearer, and penalty-free, to spell out how you are calculating the

    number of seconds in a year, rather than actually doing the calculation yourself

    A realization that the expression will overflow an integer argument on a 16-bit

    machine-hence the need for the L, telling the compiler to treat the variable as a

    Long

    As a bonus, if you modified the expression with a UL (indicating unsigned long),

    then you are off to a great start. And remember, first impressions count!2. Write the "standard" MIN macro-that is, a macro that takes two arguments and returns

    the smaller of the two arguments.#define MIN(A,B)

    ((A) 6") :puts("

    6." The reason for this is that expressions involving signed and unsigned types

    have all operands promoted to unsigned types. Thus 20 becomes a very large positive

    integer and the expression evaluates to greater than 6. This is a very important point inembedded systems where unsigned data types should be used frequently (see Reference

    2). If you get this one wrong, you are perilously close to not getting the job.

    13. Comment on the following code fragment.

    unsigned int zero = 0;unsigned int compzero = 0xFFFF;/*1's complement of zero */

  • 8/14/2019 C_lang_Ref_Raja

    38/39

    C_Lang_Ref Raja 38

    On machines where an int is not 16 bits, this will be incorrect. It should be coded:

    unsigned int compzero = ~0;

    This question really gets to whether the candidate understands the importance of word

    length on a computer. In my experience, good embedded programmers are critically

    aware of the underlying hardware and its limitations, whereas computer programmerstend to dismiss the hardware as a necessary annoyance.

    By this stage, candidates are either completely demoralized-or they're on a roll andhaving a good time. If it's obvious that the candidate isn't very good, then the test is

    terminated at this point. However, if the candidate is doing well, then I throw in these

    supplemental questions. These questions are hard, and I expect that only the very bestcandidates will do well on them. In posing these questions, I'm looking more at the way

    the candidate tackles the problems, rather than the answers. Anyway, have fun...

    Dynamic memory allocation

    14.Although not as common as in non-embedded computers, embedded systems do still

    dynamically allocate memory from the heap. What are the problems with dynamic

    memory allocation in embedded systems?Here, I expect the user to mention memory fragmentation, problems with garbagecollection, variable execution time, and so on. This topic has been covered extensively in

    ESP, mainly by P.J. Plauger. His explanations are far more insightful than anything I

    could offer here, so go and read those back issues! Having lulled the candidate into asense of false security, I then offer up this tidbit:

    What does the following code fragment output and why?

    char *ptr;if ((ptr = (char *)malloc(0)) ==

    NULL)

    elseputs("Got a null pointer");puts("Got a valid pointer");

    This is a fun question. I stumbled across this only recently when a colleague of mine

    inadvertently passed a value of 0 to malloc and got back a valid pointer! That is, the

    above code will output "Got a valid pointer." I use this to start a discussion on whetherthe interviewee thinks this is the correct thing for the library routine to do. Getting the

    right answer here is not nearly as important as the way you approach the problem and the

    rationale for your decision.

    Typedef

    15. Typedefis frequently used in C to declare synonyms for pre-existing data types. It is

    also possible to use the preprocessor to do something similar. For instance, consider thefollowing code fragment:

    #define dPS struct s *typedef struct s * tPS;The intent in both cases is to define dPS andtPS to be pointers to structure s. Whichmethod, if any, is preferred and why?

  • 8/14/2019 C_lang_Ref_Raja

    39/39

    C_Lang_Ref Raja 39

    This is a very subtle question, and anyone who gets it right (for the right reason) is to be

    congratulated or condemned ("get a life" springs to mind). The answer is the typedefis

    preferred. Consider the declarations:

    dPS p1,p2;tPS p3,p4;The first expands to:

    struct s * p1, p2;which defines p1 to be a pointer to the structure and p2 to be an actual structure, which is

    probably not what you wanted. The second example correctly defines p3 and p4 to be

    pointers.

    Obscure syntax

    16. C allows some appalling constructs. Is this construct legal, and if so what does this

    code do?

    int a = 5, b = 7, c;c = a+++b;

    This question is intended to be a lighthearted end to the quiz, as, believe it or not, this is

    perfectly legal syntax. The question is how does the compiler treat it? Those poor

    compiler writers actually debated this issue, and came up with the "maximum munch"

    rule, which stipulates that the compiler should bite off as big (and legal) a chunk as it can.Hence, this code is treated as:

    c = a++ + b;

    Thus, after this code is executed, a = 6, b = 7, and c = 12.If you knew the answer, or guessed correctly, well done. If you didn't know the answer

    then I wouldn't consider this to be a problem. I find the greatest benefit of this question isthat it is good for stimulating questions on coding styles, the value of code reviews, and

    the benefits of using lint.

    Well folks, there you have it. That was my version of the C test. I hope you had as muchfun taking it as I had writing it. If you think the test is a good test, then by all means use it

    in your recruitment. Who knows, I may get lucky in a year or two and end up being on

    the receiving end of my own work.

    Reference:

    The Complete Reference, 4th Ed

    Expert C programming - Deep C secrets

    www.Wikipedia.org

    http://www.wikipedia.org/http://www.wikipedia.org/