C - Basics, Bitwise Operator
Jinyang Li
Lesson plan
• Overview
• C program organization
• Bitwise operators
• Control flow
C is an old programming language
C (1972) Java (1995) Python (2.0, 2000)
C is an old programming language
C Java Python
1972 1995 2000 (2.0)
Procedure Object oriented Procedure & object oriented
Compiled to machine Compiled to bytecode, Scripting language, interpreted
code, runs directly on runs by another piece of by software
hardware software
static type static type dynamic type
Manual memory Automatic memory management with GC
management
Tiny standard Very Large library Humongous library
library
Why learn C for CSO?
• C is a systems language
– Language for writing OS and low-level code
– System software written in C:
• Linux, Windows kernel, MacOS kernel
• MySQL, Postgres
• Apache webserver, NGIX
• Java virtual machine, Python interpreter
• Why learning C for CSO?
– simple, low-level, “close to the hardware”
The simplest C program: “Hello World”
#include <stdio.h> Equivalent to “importing” a library package
int main()
{
printf("hello, world\n");
return 0;
A function “exported” by stdio.h
}
hello.c
Compile: gcc hello.c –o hello
Run ./hello If –o is not given, output executable file is a.out
:
C program with multiple files: naïve
organization
int sum(int x, int y) #include <stdio.h> #include <stdio.h>
#include <assert.h>
{
return x+y; int main()
void test_sum()
{ {
}
int r = sum(1,1); printf(“sum=%d\n”, sum(-1,1));
sum.c assert(r == 2); }
}
main.c
int main()
{ Compile: gcc sum.c test.c –o test
test_sum();
} gcc sum.c main.c
test.c
Run: ./test Sum.c compiled twice.
./a.out Wasteful
C program with multiple files: *.h vs *.c files
Equivalent to “importing” a package
int sum(int x, int y) #include <stdio.h> #include <stdio.h>
#include <assert.h> #include “sum.h”
{
#include “sum.h”
return x+y; int main()
} {
void test_sum() printf(“sum=%d\n”, sum(-1,1));
sum.c { }
int r = sum(1,1);
assert(r == 2); main.c
int sum(int x, int y);
}
sum.h
int main()
{
test_sum();
}
test.c
Common compilation sequence
called
Source (Binary)
gcc –c main.c object linking
Code
main.c file (Binary)
main.o gcc main.o sum.o Executable
a.out
Source (Binary)
gcc –c
Code object
sum.c
sum.c file
sum.o
(Binary)
Source (Binary) gcc test.o sum.o –o test Executable
gcc –c test.c
Code object test
test.c file
test.o
C project uses the make tool to automate compiling with dependencies.
all: a.out test
test: test.o sum.o
gcc $^ -o $@
a.out: main.c sum.o
gcc $^ -o $@
%.o: %.c
gcc –c $^
Makefile
Basic C
• C’s syntax is very similar to Java
– Java borrowed its syntax from C
If uninitialized,
Initial value
variable can have any value
Variable declaration: int a = 1;
Type Name
Primitive Types (64-bit machine)
Either a character or an intger
type size (bytes) example
(unsigned) char 1 char c = ‘a’
(unsigned) short 2 short s = 12
(unsigned) int 4 int i = 1
(unsigned) long 8 long l = 1
float 4 float f = 1.0
double 8 double d = 1.0
pointer 8 int *x = &i
Next lecture
Old C has no native boolean type. A non-zero integer
represents true, a zero integer represents false
C99 has “bool” type, but one needs to include
<stdbool.h>
Implicit conversion
int main()
{
int a = -1;
unsigned int b = 1;
if (a < b) {
printf("%d is smaller than %d\n", a, b);
} else if (a > b) {
printf("%d is larger than %d\n”, a, b);
}
return 0;
}
$gcc test.c No compiler warning!
$./a.out
-1 is larger than 1
Compiler converts int types to the one with the larger value (e.g.
char à unsigned char à int à unsigned int)
-1 is implicitly cast to unsigned int (4294967295)10
Explicit conversion (casting)
int main()
{
int a = -1;
unsigned int b = 1;
if (a < (int) b) {
printf("%d is smaller than %d\n", a, b);
} else if (a > (int) b) {
printf("%d is larger than %d\n”, a, b);
}
return 0;
}
Operators
Arithmetic +, -, *, /, %, ++, --
Relational ==, !=, >, <, >=, <=
Logical &&, ||, !
Bitwise &, |, ^, ~, >>, <<
Arithmetic, Relational and Logical operators are identical to java’s
Bitwise AND: &
Truth table (of boolean function AND)
x y x AND y
0 0 0
How many rows
if function has 0 1 0
n boolean (aka 1 0 0
1-bit) inputs? 1 1 1
2n
Operator & applies AND bitwise to two integers
( 0 1 1 0 1 0 0 1 )2
& ( 0 1 0 1 0 1 0 1 )2
Result of 0x69 & 0x55
( 0 1 0 0 0 0 0 1 )2
Example use of &
• & is often used to mask off bits
b & 0 = 0?
b is any bit b & 1 = b?
int clear_msb(int x) {
return x & 0x7fffffff;
}
Bitwise OR: |
x y x OR y
0 0 0
0 1 1
1 0 1
1 1 1
Operator | applies OR bitwise to two integers
( 0 1 1 0 1 0 0 1 )2
| ( 0 1 0 1 0 1 0 1 )2
Result of 0x69 | 0x55
( 0 1 1 1 1 1 0 1 )2
Example use of |
• | can be used to turn some bits on
b | 1 = 1?
b | 0 = b?
int set_msb(int x) {
return x | 0x80000000;
}
Bitwise NOT: ~
x NOT x
0 1
1 0
Operator ~ applies NOT bitwise to two integers
~ ( 0 1 1 0 1 0 0 1 )2
result of ~0x69
( 1 0 0 1 0 1 1 0 )2
Bitwise XOR: ^
x y x XOR y
0 0 0
0 1 1
1 0 1
1 1 0
Operator ^ applies XOR bitwise to two integers
( 0 1 1 0 1 0 0 1 )2
result of 0x69^0x55 ^ ( 0 1 0 1 0 1 0 1 )2
( 0 0 1 1 1 1 0 0 )2
Bitwise left-shift: <<
x << y, treat x as a bit-vector, shift x left by y positions
– Throw away bits shifted out on the left
– Fill in 0’s on the right
result of 0x69<<3 ? (0 1 1 0 1 0 0 1)2
=(0 1 0 0 1 0 0 0)2
Bitwise right-shift: >>
• x >> y, shift bit-vector x right by y positions
– Throw away bits shifted out on the right
– Logical shift: Fill with 0’s on left
– Arithmetic shift: Replicate msb on the left
Result of (logical) right-shift: 0xa9 >> 3 (1 0 1 0 1 0 0 1)2
=(0 0 0 1 0 1 0 1)2
Result of (arithmetic) right-shift: 0xa9 >> 3 =(1 1 1 1 0 1 0 1)2
Which shift is used in C ?
Arithmetic shift for signed numbers
Logical shifting on unsigned numbers
int a = 1; unsigned int b = -1;
a = a>>31; b = b >>30;
int b = -1; ??
b = 3
b = b >>31;
a=0?? b=-1
??
Example use of shift
int multiply_by_powers_of two(int x, int p)
{
return x << p;
}
int divide_by_powers_of two(int x, int p)
{
return x >> p;
}
Caveat: right-shift rounds down, different from
integer division “/” which rounds towards zero.
e.g. -1>>1=-1, but -1/2 = 0
Example use of shift
// clear bit at position pos
// rightmost bit is at 0th pos
int clear_bit_at_pos(int x, int pos)
{
unsigned int mask = 1 << pos;
return x & (~mask);
}
Lesson plan
• Overview
• C program organization
• Bitwise operators
• Control flow
C’s Control flow
• Same as Java
• conditional:
– if ... else if... else
– switch
• loops: while, for
– continue
– break
goto statements allow jump anywhere
goto label
while (cond) {
... for(...) {
} for(...) {
B: for(...) {
... goto error
Any control flow primitive can be }
expressed as a bunch of goto’s. }
}
A:
if (cond = false) goto B; error:
... code handling error
goto A
B:
...
The only acceptable scenario for using goto
Avoid goto’s whenever possible
Avoid goto’s whenever possible
C scope rules
• Local variable: defined within a procedure
– Scope: within the procedure
• Global variable: defined outside of any procedure
– Scope: within the file unless exported via *.h
int x = 0;
int y = 1;
void swap(int x, int y) {
int tmp = x;
x = y;
y= x;
}
int main() {
int x = 0;
int y = 1;
swap(x, y);
}
Summary
• C program’s basic organization
– *.c vs. *.h files
– Compilation and make
• Bitwise operators, &, |, ~, ^, >>, <<
– >> (arithmetic vs. logical)
• Control flow
– goto is general, but results in spaghetti code