#75 – New Bits When Shifting

When doing bitwise shifting using the << and >> operators, the data value being shifted will always shift new bits in–from the left when right shifting, or from the right when left shifting.  The value of the new bits depend on the direction of the shift and the data type being shifted.

  • Right shift
    • If shifting int or long, new bits at left match sign of the value
    • If shifting uint or ulong, new bits at left are 0-valued
  • Left shift
    • New bits at right are 0-valued

Shift operations can never result in an overflow.

Advertisements

#74 – Shift Operators

C# supports two bitwise shift operators that allow you to shift a series of bits a certain number of bit positions to the left or right.

  • <<    Left shift
  • >>    Right shift

The shift operators work on the following types: uint, int, ulong, and long.

 uint u = 0x32 << 4;    // Shift 4 bits to left = 0x320
 uint u2 = 0xAB0 >> 4;  // Shift 4 bits to right = 0xAB

Note that shifting to the left is the same as multiplying the value by 2 to the power of the # of bits shifted.  E.g. Shifting by 1 bit doubles the number and shifting by 2 bits multiples the number by 4.

 uint u = 12 << 1;      // 24
 u = u << 3;            // * 8 = 192

Similarly, shifting to the right divides the value by 2 to the power of the # of bits shifted.

#73 – Bitwise Operators

C# supports various bitwise operators for integral types.  These operators allow performing the following operations on sequences of bits: Complement, OR, AND, and XOR.

~ Operator – Complement

The ~ operator takes a single operand and performs a bitwise complement operation, flipping each bit.

 uint u = ~0xFF00C3A5;      // 0x00FF3C5A

| Operator – OR

The | operator takes two operands and performs a bitwise OR, i.e. output bit is 1 if either input bit is 1.

 uint u = 0x00FF3333 | 0x0F0F5555;    // 0x0FFF7777;

& Operator – AND

The & operator takes two operands and performs a bitwise AND, i.e. output bit is 1 if both input bits are 1.

 uint u = 0x00FF3333 & 0x0F0F5555;    // 0x000F1111

^ Operator – XOR

The ^ operator takes two operands and performs an exclusive OR operation, i.e. output bit is 1 if exactly one input bit is 1.

 uint u = 0x00FF3333 ^ 0x0F0F5555;    // 0x0FF06666

#72 – Hexadecimal Numbers

In C#, integer literals are normally specified using base-10 notation (e.g. 123), but can also be specified as a base-16 (hexadecimal or hex) number.

Each hex digit represents a 4-bit value and can therefore represent a value in the range [0,15].  Values from 0-9 are represented by their decimal digits.  Values from 10-15 are represented by the hex digits A-F.

In C#, hex literals begin with the characters “0x”.

Each hex digit represents a value to be multiplied by a power of 16.

Example: 0x1A2F = (1 x 163) + (10 x 162) + (2 x 161) + (15 x 160) = 4096 + 2560 + 32 + 15 = 6703

You can also think of each hex digit as representing four bits:

0 = 0000
1 = 0001
2 = 0010

E = 1110
F = 1111

So 0x1A2F would be:  0001 1010 0010 1111

In C#, you can use hex numbers for integer literals.

 int n = 0x1A2F;
 ushort u1 = 0xFFFF;         // 16 bits
 uint u2 = 0x12341234;       // 32 bits

Hex numbers are a convenient way of expressing integral values, denoting exactly the bits stored in memory for that integer.

#71 – StringBuilder Capacity

You can use a StringBuilder object without worrying about how much memory it has allocated internally for the strings that it stores.  The StringBuilder class will automatically allocate enough memory to store the strings that it is working with.

The Capacity property indicates the the maximum number of characters that can be stored in a StringBuilder object.  If an operation results in a string requiring more memory, additional memory will automatically be allocated and Capacity will be increased.

The Length property indicates the length of the string stored in the StringBuilder object.

By default, Capacity starts out at 16 and is doubled whenever more characters are required for a string.

 StringBuilder sb1 = new StringBuilder();    // Len=0, Cap=16
 sb1.Append("1234567890123456");             // Len=16, Cap=16
 sb1.Append("z");                            // Len=17, Cap=32
 sb1.Append("1234567890123456");             // Len=33, Cap=64

You can also explicitly specify capacity when you instantiate a StringBuilder:

 StringBuilder sb2 = new StringBuilder(100);

#70 – The StringBuilder Class

For more efficient string manipulation, you can use the StringBuilder class, which has methods that allow you to modify its internal character data without allocating a new string for each operation.

A StringBuilder instance wraps a single Unicode string and allows you to modify that string in different ways.

StringBuilder can be found in the System.Text namespace.

Constructing a StringBuilder:

 StringBuilder sb1 = new StringBuilder();    // Empty string
 StringBuilder sb2 = new StringBuilder("Sean");

Modifying internal string:

 sb2.Append(" was here");
 sb2.AppendFormat(" on {0:d}", DateTime.Today);
 sb2.Replace("Sean", "Kilroy");
 sb2.Insert(0, "Mr. ");          // Insert at start of string

Other things that you can do with a StringBuilder object:

 char third = sb2[2];            // 3rd character
 string s = sb2.ToString();      // Convert to string
 int len = sb2.Length;           // # chars

#69 – Strings Are Immutable

In C#, strings are immutable which means that they cannot be changed after they are created.  More generally, this is the case for the System.String class in .NET.

Syntactically, however, it appears that you can change the contents of a string (e.g. add a character to the end of a string):

 string s1 = "AGORA";
 s1 = s1.Replace('A', 'Z');   // Replace A's with Z's

But in this case, the original string is destroyed, a new string is allocated that contains the result of the replace operation and the s1 variable is set to point to the new string.

In practice, it doesn’t matter much to the programmer that C# strings are internally immutable, since you can “change” them syntactically, as shown above.  Immutability is important only when considering performance of repeated operations on the same string.