Fundamental C - Low Down Data |
Written by Harry Fairhead | |||
Monday, 21 November 2016 | |||
Page 2 of 2
Declaring VariablesBefore you can use a variable you have to declare it as being of a fixed type. This lets the compiler know what the variable is called and how much memory to set aside for it. It also tells the compiler how to implement operations that involve the variable. For example,
creates a variable that is suitable for storing an integer and if you use myinteger in an arithmetic expression the compiler knows that it has to use integer operations. Notice that you have to declare a variable before you use it. This generally means that C programmers gather their declarations to be at the start of the program. This isn't a hard and fast rule, however, and some programmers follow the convention of declaring variables where they are first used. Also notice that variable names are case sensitive and even though you can write long variable names only the first 31 characters are used by the compiler. We now come to the question of initialization. This is one of those many things that makes C dangerous in some programmers opinion. What does a variable contain when you declare it? The answer is often whatever was in the memory that is used to store it. C doesn't do anything that isn't essential to make sure that you can write a fast and efficient program. When you write:
the compiler simply sets myVariable as a reference to some area of memory. When the program is run, nothing is done to initialize the memory location and this means there are no overheads at all. Of course, if you use the variable without storing something in it the result is that you will find whatever was stored in the memory before. This is why it is dangerous - uninitialized variables can cause very difficult to find bugs. Notice that the system will initialize to zero global and static variables for you - see later. You can initialize a variable by storing something in it:
which does give your program something to do when it is first loaded i.e. myVariable=0 is an instruction that has to be carried out. As an alternative you can use an initialization:
In general you should initialize variables unless you have a really good reason not to. LiteralsIf you are going to initialize variables you have to know how to write values that are suitable. C has quite a range of ways of letting you specify a value and its type. For integers you can write in decimal, octal or hexadecimal. An octal constant is signified by a leading 0 - do don't write unnecessary leading zeros on decimal literals. Hex literals are much safer because they start with 0x, which isn't likely to be entered by accident. So 77 is 77 in decimal but 077 is 63 in octal and 0xFF is 255 in hex. A floating point literal is signified by having a decimal point - 1 is an integer and 1.0 is a float. You can also write an exponent as in 1E3 which is float with the value 1000. You can also use a suffix to specify the type of a literal: 1.0f is a float 2u is an unsigned int 3L is a long 4Lu is an unsigned long 5LL is a long long 6LLu is an unsigned long long Often the compiler will work out what the literal should be. For example there is no suffix for a short literal because the compiler simply attempts to fit the int literal into the short variable and if it fits it doesn't complain. When you write a literal the compiler tries to fit it into an int, if it doesn't fit it try a long and then a long long. Most of the time you don't have to specify a type for a literal, but sometimes it is essential to avoid a compiler error. For example, if you try:
you will most likely find that y is -100, which is not the correct answer. The reason for this is that the literals are treated as ints as they are within the range of a four-byte int, but the arithmetic overflows and this erroneous result is stored in y. The solution is to explicitly set the constants to LL:
which now gives the correct result. Exact Size VariablesMost of the time you can work with C's strange approach to variable types because you are targeting a particular machine. The solution to the problem of how to work with variables that have a definite number of bits is to use the stdint.h header file. This is a library that was introduced in C99 to provide a set of types that are fixed in size irrespective of the machine in use. Of course the implementation might not be the most efficient possible on the machine. The library introduces new types of the form: intN_t uintN_t for signed and unsigned integers with N bits. The only values of N that have to be implemented in the library are 8,16,32 and 64. The signed types are implemented as two's complement. Note that the implementations have to be exact and no padding bits are allowed. To use the library you have to add: #include <stdint.h> to the other automatically generated includes. So, for example:
is guaranteed to be an 8-bit variable and
is guaranteed to be a two-byte unsigned int. This all works well, but if the machine doesn't support int16_t as a native two-byte int the results could be very slow. There is an alternative which lets you specify either the minimum width that can be used: int_leastN_t or uint_leastN_t or the fastest minimum width: int_fastN_t or uint_fastN_t. For example: int_least8_t mybyte; will create a variable that is as small as possible but still greater than or equal to 8 bits. The fast version gives you a variable that is as small as possible but with the extra condition that it is fast. So, for example: int_fast8_t mybyte; will be at least 8-bits but it might be larger if it is faster to use a bigger variable type. Exactly how these are implemented is left up to the compiler writer. In practice using stdint.h is a good idea, even if you are targeting a fixed machine because it makes clear the exact size of the variables that are in use. Specifically, if you write: int myvar; then a programmer unfamiliar with the machine is left wondering what the size of the variable is, but if you use: int16_t myvar; then, even though this might map to int, it makes it clear that this is a 16-bit int. There are also macros that will create literals in the correct type: INTN_C(value) UINTN_C(value) create signed and unsigned literals with N bits. For example: INT16_C(255) creates a 16-bit signed constant for 255.
Fundamental C: Getting Closer To The MachineNow available as a paperback and ebook from Amazon.
Also see the companion volume: Applying C <ASIN:1871962609> <ASIN:1871962463> <ASIN:1871962617> <ASIN:1871962455>
Related ArticlesGetting Started With C Using NetBeans Remote C/C++ Development With NetBeans Getting Started With C/C++ On The Micro:bit To be informed about new articles on I Programmer, sign up for our weekly newsletter, subscribe to the RSS feed and follow us on, Twitter, Facebook, Google+ or Linkedin.
Comments
or email your comment to: comments@i-programmer.info
|
|||
Last Updated ( Tuesday, 11 September 2018 ) |