C_lang_Ref_Raja
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/