Wednesday, 25 May 2011

'auto' and 'register' variables

One of the questions that is still being asked in the interviews is about 'auto variables' and 'register variables'. I have never come across any practical code that uses them and dont even see any need for them being used but as I say, Interview questions dont reflect how good a coder would be and even if a person answers all questions correctly, how can we judge someone's debugging skills.

Anyway, 'auto' variables are the default local variables. When you define a local variable, it is by default 'auto'. There is no need to use it as its implicit. In the new C++ standard, C++0x, 'auto' serves another purpose and may break any C++ code using auto when compiled using C++0x.

The 'register' keyword was initially used to help the compiler optimise the performance for the variables that were read/written very often. Since the compilers have evolved, nowadays they choose to ignore the requests as they can optimize the performance better than us humans.

The following is from StackOverflow discussion:

Here's an excerpt from Section 6.7.1 (footnote 101) of the C99 standard (pdf):

The implementation may treat any register declaration simply as an auto declaration. However,whether or not addressable storage is actually used, the address of any part of an object declared with storage-class specifier register cannot be computed, either explicitly (by use of the unary & operator as discussed in 6.5.3.2) or implicitly (by converting an array name to a pointer as discussed in 6.3.2.1). Thus, the only operator that can be applied to an array declared with storage-class specifier register is sizeof.

And from Section 7.1.1, Paragraph 3 of the C++ standard (pdf):

A register specifier has the same semantics as an auto specifier together with a hint to the implementation that the object so declared will be heavily used. [Note: the hint can be ignored and in most implementations it will be ignored if the address of the object is taken. —end note]

So, this seems like another case of C and C++ having "identical" features that behave the way you'd expect them most of the time, but diverge and cause confusion other times. In this situation, I think the way C does it makes sense since it

  • is semantically closest to being correct and;
  • doesn't do things behind your back.

Fun tidbits about register

The C++ group (WG21) wants to deprecate register:

The register keyword serves very little function, offering no more than a hint that a note says is typically ignored. It should be deprecated in this version of the standard, freeing the reserved name up for use in a future standard, much like auto has been re-used this time around for being similarly useless.

Notes from the March, 2009 meeting:

The consensus of the CWG was in favor of deprecating register.

Look what the C99 group (WG14) said about register (pdf) at a meeting:

General agreement to deprecate the “auto” keyword. Should we ask WG21 to go back to the previous use of “register” (no address)? No, this will not fly with WG21.


Sample program as follows:



//Program tested on Microsoft Visual Studio 2008 - Zahid Ghadialy
#include<iostream>

using namespace
std;

int
main()
{

int
i = 123;
auto
int j = 456;
register
int k = 789;

cout<<"Address of i = " << &i <<", Value = " << i << endl;
cout<<"Address of j = " << &j <<", Value = " << j << endl;
cout<<"Address of k = " << &k <<", Value = " << k << endl;

return
0;
}



Output as follows:
Note that the address of i, j and k are very close implying that the compiler chose to ignore the 'register' keyword.

Wednesday, 11 May 2011

Example of set_union and set_intersection

Program as follows:



//Program tested on Microsoft Visual Studio 2008 - Zahid Ghadialy
#include <iostream>
#include <algorithm>
#include <vector>
#include <set>

using namespace
std;

int
main()
{

int
setOne[] = {5, 10, 15, 20, 25};
int
setTwo[] = {50, 40, 30, 20, 10, 11, 21, 31, 41, 51};

int
setOneSize = sizeof(setOne) / sizeof(int);
int
setTwoSize = sizeof(setTwo) / sizeof(int);

//Its necessary to sort if not already sorted
sort(setTwo, setTwo + setTwoSize);

vector<int> unionSetVector(setOneSize + setTwoSize);
set_union(setOne, setOne + setOneSize, setTwo, setTwo + setTwoSize, unionSetVector.begin());

cout<<"\n1. unionSetVector : ";
copy(unionSetVector.begin(), unionSetVector.end(), ostream_iterator<int>(cout, " "));
cout<<endl;

vector<int> intersectionSetVector(min(setOneSize, setTwoSize));
set_intersection(setOne, setOne + setOneSize, setTwo, setTwo + setTwoSize, intersectionSetVector.begin());

cout<<"\n1. intersectionSetVector : ";
copy(intersectionSetVector.begin(), intersectionSetVector.end(), ostream_iterator<int>(cout, " "));
cout<<endl;

cout<<endl;
return
0;
}


The output is as follows:

Tuesday, 3 May 2011

Example of 'Set' and operations

Example of Set and operations as follows:



//Program tested on Microsoft Visual Studio 2008 - Zahid Ghadialy
#include<iostream>
#include <set>

using namespace
std;

int
main()
{

int
someInts[] = {3, 6, 9, 12, 15, 18};
int
someIntsSize = sizeof(someInts) / sizeof(int);

set<int> someSet (someInts, someInts + someIntsSize);

cout<<"\n1. someSet : ";
copy(someSet.begin(), someSet.end(), ostream_iterator<int>(cout, " "));
cout<<endl;

//Insert some more elements
someSet.insert(0);
someSet.insert(10);
someSet.insert(20);

cout<<"\n2. someSet : ";
copy(someSet.begin(), someSet.end(), ostream_iterator<int>(cout, " "));
cout<<endl;

//Upper Bound means the next greater number
set<int>::iterator it = someSet.upper_bound(5);
cout << "\nupper_bound(5) = " << *it << endl;

it = someSet.upper_bound(10);
cout << "\nupper_bound(10) = " << *it << endl;

//Lower bound means either equal or greater number
it = someSet.lower_bound(5);
cout << "\nlower_bound(5) = " << *it << endl;

it = someSet.lower_bound(10);
cout << "\nlower_bound(10) = " << *it << endl;

//Equal Range returns a pair
pair<set<int>::iterator,set<int>::iterator> retIt;
retIt = someSet.equal_range(5);
cout<<"\nequal_range(5) - lower bound = " << *retIt.first <<
" upper bound = "
<< *retIt.second << endl;

retIt = someSet.equal_range(10);
cout<<"\nequal_range(10) - lower bound = " << *retIt.first <<
" upper bound = "
<< *retIt.second << endl;

cout<<endl;
return
0;
}


The output is as follows: