Random C things – part I

Hi There ! It’s been a while since I posted – I have just been busy with life  (read  “lazy” or occupied with random things). But, am back now.

This is not really a blog post per se. I just felt like putting up a refresher to people who are familiar with C programming. It’s in a concise question and answer format ; won’t take too long ! Go ahead … 🙂

01. Can two different type of variables be declared with same name ?


Example : int a ; and enum a { b = 2, c};

The answer to this is : Yes – if they are not in same scope (local / global scope) and variable name is not used for a “#define” constant. 

If both are in local or both are declared in global space – then there will be a clash in the symbol name space.

02. What happens to uninitialized const variable ?


It gets initialized to zero. Example : const int a; declaration will set “a” to zero and cannot be modified. Keyword “const” makes the variable a “read-only”.

Even when we use keyword “static” the variables are by default initialized to zero.

03. Can we have a structure with bit fields ? How to achieve this ?


Yes, we can!

For example :  If you want a structure that holds two variables whose values can range from 0 to 15 then , all we would need is two fields with 4 bits each. This can be achieved using a declaration as below :

struct sample{
uint8_t var1:4; // first variable 4 bits
uint8_t var2:4; // second variable 4 bits
};

04. What is structure packing?


We would want to make sure we are packing the structure variables “efficiently” – specially on embedded memory limited systems.

Example :
struct noPack{
char b; // one byte + one byte  implicit padding
uint16_t data; // two bytes
char c; // one byte + one byte implicit padding
};
a total of "6 bytes"

But, if we re-arrange this :
struct withPack{
uint16_t data; // 2 bytes
char b; // one byte
char c; // one byte
};
a total of "4 bytes" 

Yes, we saved 2 extra byte assignment just by rearranging and packing 
efficiently ! 
Usually the trick is to pack the structure starting with the biggest 
size data type (in this case (sizeof(uint16_t)) > sizeof(char)) 
to lowest size

05. What is integer overflow  ? How can we handle this ?

Yes, there can be problems when you cast a larger data type to smaller one -i.e., loss of information. Consider the example below :

uint16_t func1(uint8_t a ){
//do some operation and return
return (a+100);
}
Suppose, this function is used as below :
uint8_t temp = func1(10); // result returned is 16-bit
//but, implicitly gets truncated to 8-bit 
//(depending on the compiler's behavior)

Suppose input variable “a” was set to 0xFF  (max value for an 8-bit integer), adding a value of 100 requires more than 8 bits to hold the result of addition – resulting in an overflow when the value returned is stored in an 8 bit integer – “temp” in this example.

And, trust me when I say these can result in hard bugs to catch when they happen in production code. So, please take care of scenarios involving implicit conversions such as this ! Make sure you have fixed all the warnings your compiler spits out or at least take a look at the warning messages.

06. Why will I ever use a union?

Unions allow data members that are mutually exclusive to share memory. This is important specially in the embedded system cases where memory is a scarce resource.

For example : If you implementing protocol handler with different kinds of messages that can be exchanged, we could handle the different message types and their allocations as below on an embedded system :

// Declare a union with all types of different messages to be handled.
// All message types in the union shall share same memory.
// Only one of these messages would need to be handled by protocol implementation at 
// a given time -this means they are mutually exclusive and hence would be a good idea 
// to share the memory.

typedef union
{
  protocol_req_identity_type      identity;
  protocol_req_challenge_type     challenge;
  protocol_req_notification_type  notification;
} protocol_req_msg_union_type;

// Generic format to decipher a protocol message
// check mnessage type and cast to appropriate message type in structure.
typedef struct 
{
  protocol_msg_type_enum         msg_type; // can be a identity , challenge or a notification
  protocol_req_msg_union_type    msg_union;
}protocol_req_msg_type;

07. Why do we need Enum ?

Well! One reason I can think of is – it’s not only important that we write efficient code but also readable code. Enum(s) provide us a way to add readability to our code.

Suppose you are writing some api and want to return custom status codes -1 , 1 and 2 – to mean different return status, to the caller. We can write human readable code as below, instead of using the status codes as numbers (-1, 1 ,2) directly.

//custom verbose return codes
typedef  enum codes{
CUST_ERROR = -1,
CUST_SUCCESS = 1;
CUST_RETRY = 2;
}cust_status;

// function / api that returns a status code 
cust_status func1(){
// Do some operation and return status codes to caller
// set error as default status
cust_status status = CUST_ERROR;

//you want the user to retry later
{
//..
status = CUST_RETRY;
}
//..
{
//do some processing 
//everything went fine
status = CUST_SUCCESS;
}
//..
return status;
}

//caller checks the returned status code 
int main(){
if (CUST_SUCCESS == func1()){
printf("Success\n");
}
else if(CUST_RETRY == func1()){
printf("Retry the operation later\n");
}
}

08. What is the difference between “#define” of a constant and declaring it “const int” ?


As a novice programmer, when I started with C , I wondered why were there two options to do the same thing – which one is to be used ?

#define TEST_VARIABLE 100      // pre-processor directive
int const TEST_VARIABLE = 100; // constant variable

#define is essentially a preprocessor directive. The C preprocessor shall replace all occurrences of the given variable in the code with the value before compiler compiles the code.

Whereas const is acted upon by compiler. It only indicates that the variable is “read only” , all rules of a variable apply to it as well. But, if a compiler doesn’t optimize and replace these occurrences, then there will be an overhead.

When you don’t really care about the types  -for example : a variable that holds a fixed constant could be #defined !   Also, if you are designing in a large team : #defines may be a good option as they throw a compile error when we redefine a local variable with same name, as in the example below.

//Global variable 
int const trials =10;

int func(){
// Someone decides to use same name for a local in the function but
// you intended to use global definition at a later point.
int trials= 20; 
// defining variable "trials" with a #define would have 
// thrown an error here.

//...
// few 100 lines of code later
//...

//suppose you intended to look up the global variable "trials"
int number_trials = trials; // this has 20, not the 10 that you wanted!!
}

09.  Can I assign a pointer to constant int to a pointer to an integer ?


You can ! But, don’t !!

Example :

const int * constptr; // pointer to constant integer

int* ptr; // pointer to an integer

const int var1 =10; // constant integer

constptr = &var1; // assign a const integer (const => read only)

ptr = (int*) constptr; //valid , but don’t !

*ptr = 15; // change value pointer – run time error !!

10. Compiler and volatile qualifier in C


Compilers with optimization enabled try to make code smaller and faster based on some rules.  Volatile keyword is used to indicate to compiler to “not optimize”.

There are cases where a variable may be updated in ways unknown to the compiler – such as :

  • Memory mapped input/output – peripheral registers,
  • Modification via signal interrupt – Global modified/accessed by other functions or ISR.
  • Shared global variable in multi-threaded programming

basically, where the updates made to the variable are not in the local scope of the code block. When this keyword is not used, the variables are cached to a CPU register or optimized out by the compiler.

“Volatile” ensures that the variable reads and writes are not optimized away.Consider the example for volatile usage below :

If you have a global variable (named value_to_write) that is shared between the main program that writes value from this variable to a port and an ISR that writes to this variable. We can have three cases that will have different behavior based on compiler optimization state and volatile qualifier is used or not.

  1. No compiler optimization : In this case , the main program code is not optimized and the ISR updated value gets written to the portX in main program
  2. With compiler optimization : In this case, the compiler looks at two different code blocks, each with variable named value_to_write as shown below. Since the compiler optimization is ON, compiler looks at main code block and unable to find updates/writes to the variable “value_to_write” , decides to optimize it out. Due to this optimization, only one value gets written to portX – 0, not the one updated by the ISR, which you wanted. This now calls for “volatile” usage.
  3. With compiler optimization enabled and volatile qualifier – now, if the variable value_to_write has a qualifier called “volatile” , although the compiler does not see a write to this variable in main code segment , it does NOT optimize it out. In this case portX will have the value updated by ISR, as expected.

volatile.png

 

But, there are some things to consider before using Volatile qualifier and they are listed here. Do check this link.

Yes, each of these topics deserve a separate blog. But, that’s all for now in this blog. Keep decoding !~

S for STATIC

Static

Static is a keyword  in C (also in C++/Java) used as storage or linkage class specifier in C. Storage indicates how the variable is to be stored in memory and linkage specifies the linkage scope to be applied during the linking process. There are various storage classes in C namely – auto, register , const and static. There are linkage specifiers such as extern or static. In this blog, we are going to understand the various facets of the keyword “static”. For a beginner or a new programmer, this can get confusing. But, not after we decode this today ! So, let’s begin.


Usage Scenarios in C

Static can mean different things based on different contexts of usage. There are three types of usage that I can think of in C:

a. Static to declare a global variable in C

Suppose you have written a .c file with following :

// File : test.c 

static int a; // global static variable

void func(){

int x;

printf(“Static variable value is %d \n”, a); // can access static variable 

}

In the example above declaring variable “a” static essentially restricts the usage of variable “a” to only inside the compilation unit / translation unit or the given “.c” file. No other file in your code can access this variable. So, in this scenario it is not really controlling the storage aspect but the scope of the variable. The scope is limited to the given file – meaning the functions inside this “.c” file alone can access or use the variable. Hence, static in this case essentially specifies “internal” linkage as opposed to using extern keyword usage – that specifies “External” linkage (note to self : we shall cover extern in the another blog).

b. Static to declare a variable inside a function in C

A variable declared “static” inside the scope of a function retains the value even after we exit the function – across multiple calls. By default variable inside function are treated as “auto” and are allocated on function stack ; but static is allocated in .DATA or .BSS section of memory.

To understand this scenario of usage consider the example below :

//Function with static variable

void func(){

static int counter; // static local variable in func().

counter++; // increment counter to count function calls

printf(“Call counter is %d” , counter);

} // counter’s state is preserved even after we hit this point. (auto variables are lost)

// Example multiple calls to function func() above :

void caller1(){

func(); // first call

}  //after this call , the function prints “Call counter is 1”

void caller2(){

func(); //second call

}//after this call , the function prints “Call counter is 2”

c. Static Function in C

The scope of these functions is limited to only the file they are contained in. We can think this as a way to attain “data encapsulation” in C as we see in OOP languages such as C++/Java.

Methods without static keyword are public while the ones with “static” keyword are “private” to the compilation unit / translation unit (the .c file).

Default Storage Specifier Rules

  1. Variables declared inside a function are considered “auto”
  2. Functions declared within a function are treated as “extern”
  3. Variables and functions declared outside a function are considered “static”, with external linkage

Static in c++

  1. In C++ it does not really specify a storage class. When a variable of a class is declared static (example variable named obj in the example below), it essentially means that all objects of that given class (exObj1  and exObj2 below) share same variable instance.
  2. If a function or member variable is declared static (example : variable named sample in the example code below), then it can be accessed without a  class object – using just the class name (check usage in cout “Example::sample”  below). This essentially means that the static member is associated only with class not the instance of the class or the “object”. It requires no instance of “this” operator.
  3. In case of inheritance, static “public” variables in the parent class are shared by the derived classes as well ; meaning a copy is not created. Whereas if they are declared “private” in parent class, then the derived classes cannot view or use the variable.

//Example.h

class Example{

public:

static int sample;

Example(); //constructor

~Example(); //destructor

};

//Example.c

//constructor counts the objects created

Example::Example(){

static int obj; // static variable

obj++;

cout<<“Object counter “<<obj<<endl;

}

//Test.c

#include “Example.h”

int main(){

Example exObj1 ; // when this is created constructor prints “Object counter 1”

Example exObj2; // when this is created constructor prints “Object counter 2”

cout<<“Accessing  public static variable without object : “<<Example::sample<<endl; // accessing static member without object

}


Initializing and defining static

By default all static variables that are not initialized are set to zero. They are initialized at compile time. Static variables contained within a “.c file” limits the usage of variable to within one compilation unit/translation unit. But, if they are declared in a header file and this header is included in multiple .c files, then there will be multiple copies of the same variable (one copy per .c file). This kind of defeats the purpose of declaring it as “static” to limit the usage scope to specific translation unit. So, if you really want to limit the scope, just put it in the .c file and use.


Static variables in Memory

If you have read this previous blog on “Memory and Program“, you would know where the static variables go to in the memory when you use them in your program. If the static variable is initialized it goes into the .DATA section where as uninitialized static variables go to the .BSS (Block Start Segment).

That’s all for today folks ! Isn’t low level coding fun !? ;). Until next time – keep decoding ~!

Talk a Bit about Bits!

Why Bits?

Given a high-level system, the smallest unit we can define is a Byte. A byte consists of 8 bits of information. Bit-wise hacks are needed if you want to operate on data units smaller than a byte. Though the inputs to these operations is a byte, they operate on each bit of the byte to yield the output. As an embedded engineer, I see many use-cases for these:).

If you want to have a bitmap for some book-keeping or have to run compression algorithms on data or packing the data for efficient transfer across the network – you would need bit manipulation!

So, let’s decode this today.


Bitwise operations

The bit-wise operations supported are :

  • AND: &
  • OR: |
  • XOR: ^
  • NOT: ~
  • Bitwise Left Shift : << and
  • Bitwise Right Shift : >>

Shown in the table below are the various operations performed on two bits a and b.

a b a&b (AND) a|b (OR) A^b (XOR)
0 0 0 0 0
0 1 0 1 1
1 0 0 1 1
1 1 1 1 0

Table 1. Bitwise operations summarized

Note that these are different from the Boolean operations “&&” and “||”. Boolean operations result in only Boolean output True of False (operate on inputs converted to Boolean expressions) while bit-wise operations have result in integral form short, int, char, unsigned, bool, long etc, after performing the operation at bit level on given inputs (need not only be Boolean).

Usage example :

AND operation can be used to check if a particular bit is set
OR operation can be used to SET a particular bit
XOR operation can be used to RESET/CLEAR a bit

Bit Shift operators

The left shift “<<” is an arithmetic operator that can operate on signed integers. The operation of shifting a number “a” to left by “n” bits yields the same result as multiplying “a” by (2 power n).

Similarly, the right shift operator “>>” on the unsigned integers yields same result as dividing “a” by (2 power n).

During the shift operations, the emptied bits are populated with zero for positive integers and “1” for negative integers. This is because post the shift, padding operation uses the MSB  (most significant bit) which is used to indicate the sign.  Shown below in Fig(1) are the example of bit shifts on unsigned 8-bit data (indicated by bits B0 to B7).

shifts.png
Fig 1. Bit shift operations

Result storage in C with bit-wise operations

When we use bitwise operations, the result of the operation is stored in a temporary variable. If we do not assign the operation to a variable it is LOST!! So, in the example below- if you expected it to print 12, it would still print value contained in a, that is 3.

For it to print 12, we would need to replace the line with the shift operation with the one shown in BLUE. We need to assign back the operation to the variable of interest – in this case, the result shall be stored in the variable “a”.

We can also combine the assignment operator into the expressions as shown in RED.

int main()
{
int a = 3;
int n = 2;
// operation : Left shift variable "a" by "n=2" bits
a<<n; // use a = a<<n; 
// or could  be written as : a<<=n; 
printf("Result  is %d", a);
}

Usage

We can use bit operations for book-keeping, packing data, extracting bit level info from some packed data, condition checks, reading a memory mapped I/O register, encryption, compression, checksum, endianness conversions when using sockets and so on. In this section, let’s go over some examples of usage.

Trick to efficient condition checks

Some time ago I was asked to write a CSS parser for this project on an embedded processor. And, obviously, I was constrained by CPU cycles I could use for this and also the memory consumption. So, I had to make sure I parsed the data exactly once, to extract information and also see if I can make the entire implementation processor cycle and memory friendly. I essentially had to extract URLs from CSS data and I was parsing the data and checking for characters “u”, “{” and “}”.

From ASCII table these have values :

‘u’ is 0x75

‘{‘  is 0x7B  and

‘}’ is 0x7D, only the right 4 bits differ and last bit is 1, picking all the fields that are set in all three yields 0x71, that shall be used as a MASK next.

example css data :  
#tag-id1{ ..text...url("http://www.geekgirldecodes.com") }
// Mask is 71 to match 'u' '{' '}' subset 
// Suppose pChar points to characters in the String being scanned.

// Without below MASK check, if we directly went to check against three 
// required characters u , { and } : we would end up performing these three 
// checks for all ASCII characters there are.

while((*pChar)&&(!(*pChar & MASK == MASK))){
 pChar++; // if it does not match subset , keep moving ahead on string
 }

// But, with ABOVE mask, we will only perform below match with 'u', '{' and '}' 
//only on 8 character subset, that may match the MASK "0x71" (between 70 to 7F)
 if(*pChar == 'u'){
 // do some operation
 }
 else if(*pChar == '{'){
 // do some operation
 }
 else if(*pChar == '}'){
 // do some operation
 }

Book Keeping bitmap

Suppose you want to keep track of occupancy of  8 seats in a room. If you put up some sensors that can detect when a person sits and notifies your system, the code designed for bookkeeping can use a bitmap internally.

Once the sensor on the seat detects a signal and your system needs to update the status, all this would need is an 8-bit bitmap, with each bit set aside per chair. This bit can be set to 1 if the seat is occupied else 0. To look up if seat 7 is occupied or not – we only need to check if this bit corresponding to seat number, is set in the bitmap as in below example code.

// Set aside 8 bits : 0000 0000 (8 bits for 8 seats)
// If a bit is set in the bitmap, it indicates seat occupied :
// example bitmap is 0100 0000 (7th seat occupied)

bool isSeatOccupied(int seatNumber){
return (bitmap & (1<< seatNumber)) ;
}

Obviously, you don’t need to do this if you are not a memory constrained system. I am giving this example to give you a feel of how you could use it if you needed to.

This would be useful in a memory constrained systems – like micro-controllers. While monitoring various I/O pins we could maintain a bitmap and use this type of implementation to check if a certain pin is set or not.

Packing data 

Say you want to transfer data over limited Bandwidth network. And, we have the following information to be transmitted :

id that can range from 0 -125  
Another field with range 0 - 257 
A flag with state information of 4 different states

How would you pack this data efficiently ?

Design a packet structure to do this , implement  pack() to  pack the data in the packet structure designed  and an unpack() function that reads the data packed.

Do mail me your answers @ decodergirlblog@gmail.com


Also, if you want some more bit manipulation tricks: Check here

But, I do hope that you don’t use for unnecessary use cases, just because you know how to and also want to show you can write tricky code ;). Make sure you write code that you will be able to easily understand and importantly be able to debug if any issue crops up at a later time!

In general when we use bit tricks, it’s a good thing to leave comments for those who may inherit your code.

So, until next time- keep decoding.

Also, if you have used any bit tricks in your code, do let me know in the comments below. 🙂

Recursive Functions

The  two pictures above form the essence of this blog. Essentially, we will look at what recursion is. It’s  a good idea to read about Functions and Stacks before going ahead.

In this write-up I plan to cover what recursion is , how you could write your own recursive function, things to be wary of while using recursive functions and of course a take on recursion versus iterative methods.


What is Recursion ?

Recursion refers to self-referencing. If a given problem can be solved for input “n”,  by representing the the solution for case “n” in terms of calls to the same function for cases other than “n”, it is recursive!

So in essence, recursive functions refer to functions that call themselves repeatedly until an exit condition is met. Note : If you forget an exit condition, the function will run forever eventually resulting in stack over flow !!

There are also recursive data types (structures that have an element of their own type, example linked list) that we will not be looking at today.

Writing your own recursive functions

One of the tricks to writing recursive function is to understand the pattern in the problem and creating a “recursive formula “or the “recursive action” you need to perform.

Let’s consider a really basic example. Say you need to write a function that will take an input “n” and return the (n)th odd number in the arithmetic series of odd numbers.

Now, let’s take a few input values “n” (call it the input Term) and the corresponding odd number f(n) (the Value we are looking for) in Fig (1) below under Block A. Looking at the table, we can identify a generic pattern that (n)th number is the previous value plus 2. So, we get a generic recursive formula : f(n) = f(n-1)+2 , essentially value (f(n)) for input term “n” is the previous value (i.e., f(n-1))plus 2.

We can use this recursive formula to write our recursive function for positive integer inputs, as shown in Fig(1) below under Block B.

recur.png
Fig(1). Recursion function and Recursive formula

A recursive function can be split into two blocks of execution:

  1. The Base case that is required in all recursive functions – for this defines the EXIT condition. We should know when to terminate the recursive call. There may be one or more base cases for our recursive function.
  2. Remaining part of the function shall contain recursive call to self and in some cases post processing is also required after the recursive call [example, in this case is “adding 2” operation after the recursive call]

Referring to Fig(1), for the base condition, we can take a trivial case as input. Let’s take n=1 case as the base or exit condition, the first odd number to be returned is 1.

For other cases, we can return expected value using the generic recursive formula we derived. Suppose your function is called oddNumber(n) instead of f(n), then the else part in Fig(1) Block B, shall be :

return oddNumber(n-1)+2;

This technique can be reversed to decipher what a recursive function does. If you are given a recursive method, all you have to do is look for the recursive formula in the function and start substituting valid value terms  “n” to be passed, starting with the base case values. The substitution method shall help you get an idea of what the function value represents, in the example,we can see that the values are all odd numbers and know that the function essentially returns nth odd number for given input n.

Other common examples of recursive functions-

  • Fibonacci series :

Expected value f(n)  : 1,1,2,3,5,8 and so on … 

Fibonacci value f(n) at nth position is a function of previous two values f(n-1) and f(n-2)

Recursive formula for Fibonacci is : f(n)=f(n-1)+f(n-2)

Base case here requires at least two values, so n=0 and n=1 case which return 1, shall be considered the exit condition when we write recursive function

  • GCD of two numbers : Greatest common divisor , highest common factor or the highest common divisor.

Greatest common Divisor is given by Euclid’s formula (the recursive formula to be used) : gcd(x,y) = gcd(x, x%y), recursive calls end when second term is zero ( or y is zero) , when y is zero, x is the greatest common divisor.

  • Same principle can be extended to  tree or graph traversals. Will be covering these in another blog.
  • These are the real use cases where we would prefer a recursive implementation 😉

Before we go to the next section, I have one question for you to solve.

What does the recursive method below do assuming input n is a power of 2 ? 🙂

Mail me the answer at decodergirlblog@gmail.com

// Note : Assume n is a power of 2 and log is base 2.

int func ( int n ){

if(n<=2) {

return 1;

}

else{

return func(n/2)*log(n);

}

} // end of function


Iterative or Recursive

Iterative refers to implementation using no self referential calls,implemented using loops.

From this blog entry , we know that the stack keeps growing as and when function calls are made. This holds good for recursive functions as well. A stack frame is allocated for each invocation of the recursive function. This means to say, there will be “n” stack frames allocated for an input “n”.  If we miss an exit condition or the base case,  there will be no end to the recursive calls, and because of the allocation of stack frames plus the fact that stack memory is limited resource, we will run out of stack space resulting in “stack overflow”. If you are a memory constrained system, you would be better off getting rid of recursive calls for solving trivial problems (Fibonacci, factorial etc), iterative will not allocate any extra memory, it will only update the loop variables in these cases. But, recursive functions offer cleaner, elegant solutions for problems involving “divide and conquer” technique (merge sort) and also the tree traversal problems.

We would need to know the depth of recursion we are aiming for and the stack memory available and the time constraints we need to work with before we think of recursive solutions. Essentially, know the constraints you have to work with. Recursive solutions take extra space and also extra time (due to usage of system stack) for solving the problem, but offer cleaner looking and/ elegant solutions.

Now, think of this :

What if we have a way to get the space consumption as in iterative case and also have the elegance of a recursive function : this is an optimization for recursive functions – called the tail recursion !

Will be writing a tidbit about this soon. Until then, keep decoding !

Byte Ordering

What is Endianness?

Endianness or Byte ordering refers to two different ways of storing multi-byte data in memory by the processor. In the embedded world where the data memory is shared and there is some hardware writing data to this block for some other piece of hardware to consume, it becomes important to understand and agree upon the endianness.

Network and Host Byte order

Yes, same applies to over the network data transfer protocols, in case you are familiar with them. The network uses big endian format while the end device may be little or big endian – hence we have the htons() and ntohs() socket level apis made available for usage. htons refers to “host to network” while ntohs refers to “network to host”  byte order conversions.


Examples

Consider a 16-bit integer in hex format 0x1234. This is represented in a “little endian” system with lower order byte first “34”. And,is represented in a “big endian” system  with higher order byte “12” first as summarized in the table below.

Address Little endian Big endian 
0x4000 34 12
0x4001 12 34

Example 32-bit data : 0xABCD1234

Address Little endian Big endian 
0x4000 34 AB
0x4001 12 CD
0x4002 CD 12
0x4003 AB 34

Detecting  the Byte order

Now that we know what big and little endian is, let’s see how we could potentially identify the endianess of a system.

Let’s assume we have a integer variable with value set to 1 – represented on a 16-bit system as 0x0001. If the first byte is 1 (that is data at lower address) then, it a Little endian system else it is a Big endian system. To check if the system is little endian we could write the sample program below.

boolean isLittleEndian()

{

int i = 0x0001;  // 16-bit variable

char* a = (char*) &i; // size of char value is a byte (8 bits)

return (*a)?1:0; // terenary operator (condition?value_if_true value_if_false)

}

If above returns true – the system is little endian else the system is big endian.


Conversion

As I had briefly mentioned above, the socket libraries support api’s for conversions such as htons() and ntohs(). Now, let’s see how we could implement our own functions for this.

htons() is used to convert from host to network order [hton] for short variable [s] : that is little endian to big endian.

 As seen in the example below, all we have to do is swap the bytes passed. Do check the post about bit level operations to understand the trick used here.

Address Little endian Big endian 
0x4000 34 12
0x4001 12 34

uint16 htons(uint16 input)

{

//reuse the endian check function

if(isLittleEndian())

{

//host is little endian – conversion needed

//use bit manipulation tricks to swap the bytes in-place as below

return ((input&0xFF00>>8)|(input&0x00FF<<8));

}

else

{

//this means it is in big endian format

// no conversion needed

return input;

}

}


That’s all in this tidbit.

Until next tidbit, keep decoding ! Happy programming !