skip to main |
skip to sidebar
Have you ever wondered if you can really change the value of a constant variable. Well it's not that difficult, So let's get down to the business right away.
The output of the above program will be "10 and 10", even though you have changed the value through a pointer. The reason is that the compiler either caches the constant value in the register or replace the actual value in the code(e.g: printf("%d\n",x); will become: printf("%d\n",10);).Note:1) The above program will output "10 and 20" if we replace the last "printf" statement with "printf("%d\n",*ptr);", but that's not the point here. We want to display the new value with the constant variable itself.2) "const_cast" is not must in the program. You can use old C style casting as well.So what should we do to fix this? The trick here is to use a "volatile const" variable instead of just using "const". Now why "volatile"? Well you might have known "volatile" construct is used to stop compiler for optimizing away the variable(I won't go into detail of volatile variables, because it's a separate long topic). Now with this construct the variables value will always be taken from the memory and not from the cached register(optimized way). Now re-run the program with the changes I have just mentioned:
The output is just the way you wanted: "10 and 20". :)
As I said in my last blog, I will be talking about C Bigraphs this time. These Bigraphs were considered more readable and replaced some of the nine Trigraph characters.List of Bigraph characters are so follows:
<% {
%> }
<: [
:> ]
%: #Now let's rewrite the program that I wrote in my last blog. But this time I will use these Bigraph characters.
Now this program didn't work on Visual Studio 2008. So apparently it's compiler does not conform to C99 ANSI standard. But I was able to compile it with the help of online compilers. And also you'll be able to compile it with the GCC.Anyhow another important difference Trigraphs and Bigraphs is that:Trigraph characters are "Synthetic Sugar" which is handled by the preprocessor, on the other hand Bigraph characters are handled during tokenizaton. This also handles an important issue which existed with the Trigraph characters. Let us see the problem by an example:
This program prints 'Hel<%lo'. But if we replace BiGraph character '<%' with the corresponding TriGraph characer "??<" then the printed value will be 'Hel{lo'. Because the preprocessor replaces the trigraph characters before actual compilation is done. Where as bigraph characters are handled during tokenization, so the bigraph character within the string token is not replaced.
In C programming language trigraph is a sequence of 3 characters in which first two characters are always '?' . Three characters combined represent a single character."The reason for their existence is that the basic character set of C (a subset of the ASCII character set) includes nine characters which lie outside the ISO 646 invariant character set. This can pose a problem for writing source code when the keyboard being used does not support any of these nine characters. The ANSI C committee invented trigraphs as a way of entering source code using keyboards that support any version of the ISO 646 character set." (Source: http://en.wikipedia.org/wiki/C_trigraph)List of Trigraph characters are as follows:??= #
??/ \
??' ^
??( [
??) ]
??! |
??< {
??> }
??- ~Now let's see a sample program that I wrote using some of the trigraph characters:
These trigraphs are only a synthetic sugar. The preprocessor replace them with the corresponding single character before doing the actual compilation.
In 1994, C standard was ammended and Bigraph character were introduced, which are considered to be more readable. I will talk about them in my next writing.
You might be surprised, but the in C++, constructors are also available for the built in primitive data types e.g int, char, float e.t.c. But you need to explicitly invoke the constructor.Let me try to give some examples:For the regular default initialization, use the following code:int myIntValue = int();float myFloatValue = float();both of the above variables will be initialized with the zero value.Of course you can also give any other initialization value to the constructor as well, e.g.int myIntValue = int(10);float myFloatValue = float(10.1);or something like:char myCharValue(65);But note you can not use the statement like the following:int myIntValue();because compiler will take this a prototype for a function, and when we'll try to use myIntValue, it will give a linking error, because of course no function with prototype "int myIntValue()" exist.You might be saying, why would I use that statement, that doesn't seem to be helping me much. And why don't I use the often used initialization statements like: int myIntValue = 10; Yes you are right on this, but read forward and you will find it's use when we use dynamic memory allocation.For the dynamic memory allocation use the following code:int *myPointer = new int(10);orint *myPointer = new int();Now with the simple dynamic allocation statement(without constructor) :int *myPointer = new int;The above statement will not initialize the new int to any value, it still has a garbage and we will have to explicitly initialize the value. So the great thing about using the constructor in dynamic memory allocation is that we can save a statement, and initiate the data type in the single statement.
Today I was going through MSDN and read that Boxing and Unboxing are 20 and 4 time more expensive than assignment respectively, Now damn!!! that's too expensive than I initially thought. Now without going into too much detail let me tell you what really happens during boxing/unboxing ;which is the cause of a big performance hit.
What is boxing/unboxing?Boxing is the process of converting a value to the type object, or to any interface type, implemented by this value type. When the CLR boxes a value type, it wraps the value inside a System.Object and stores it on the managed heap. Unboxing extracts the value type from the object. In the following example, the integer variable i is boxed and assigned to object o.
How does boxing work?Suppose we have the following code:Mystructure structobj;object refobj = structobj;Now we know that structures are value types and are stored on the stack, And the object is a class which is reference type whose data will be stored on heap(ofcourse the pointer to the heap is stored in stack, e.g object "refobj" in this example).Now here the CLR will do the following steps implicitly in order to convert a value type into a reference type:1) Load the "structobj" pointer.2) Calcualte the size of the value type.3) Create a new object and allocate it's memory on the heap, big enough to hold the value type. Memory allocated on heap is always greater than the overall size of the value type because CLR stores some extra header information stored for every reference type.4) Store the new reference type pointer in the register.5) Copy data of value type to the heap.6) Load the destination reference type pointer.7) Assign the new created reference to the destination reference object.Here the significant overhead is attributed to the heap allocation and copying of value type state.How does unboxing work?Supose we have the following code:Mystructure structobj = (Mystructure) refobj;Now here the CLR will do the following steps implicitly in order to convert a reference type into a value type :1) Load the reference of the boxed value.2) Load the destination value type.3) Check the object instance to make sure that it is a boxed value of the given value type. If not exception is thrown.4) De-reference the boxed value reference, and copy data to the destination value type.Now clearly unboxing is way cheaper than boxing. Note that the boxed type which is on heap will eventually be collected later by the garbage collector(if we no longer have a reference to it).At all cost we should think twice before using boxing/unboxing. Because firstly reference type takes more space than the value type, PLUS it has a lot performance implications.