CSc 352: Systems Programming & Unix

advertisement
CSc 352: Basic C Programming
Saumya Debray
Dept. of Computer Science
The University of Arizona, Tucson
debray@cs.arizona.edu
What’s new relative to Java?
• Some syntactic differences
– a lot of the basic syntax is similar
• assignment, conditionals, loops, etc.
• The biggest differences are conceptual
– procedural rather than object-oriented
• no notion of classes and inheritance hierarchies
– much closer to the machine
• debugging sometimes requires thorough understanding of what’s
going on at the machine level
– explicit dynamic memory management (malloc, free)
– pointers
2
A simple program
a simple C program
that prints out “hello”
Points to note:
• execution begins at main(): every program must have one
• printf() is a standard C library routine
3
A simple program…
invoking the C compiler
compiler
warning
executable file produced
by compiler
executing the program
4
Gcc options: -Wall
gcc –Wall generates warnings on questionable constructs
• if no return type is specified for a function, it defaults to int
• need to supply prototype for “printf”
5
Fixing the compiler warnings
specifies prototype for printf()
specifies return type explicitly
6
Summary
• execution starts at main()
– every program should have one
• the return type for a function defaults to int
– should specify explicitly: good style
• need to supply prototypes for functions imported
from elsewhere (e.g., standard libraries)
– specified using “#include …”
7
Simple declarations and statements
two uninitialized global
variables, x and y, of type
int
a variable, z, of type int,
that is local to the
function main; initialized
to 12
print format specifier:
%d = “print a decimal
value”
simple arithmetic
expressions and
assignment statements
8
Simple conditionals, while loops
if statement
while statement
error message:
sent to stderr
return value communicates
normal/abnormal execution
9
For loops
10
Function calls, recursion
function call
recursion
11
Formatted Output: printf()
• takes a variable no. of arguments:
text: Ch. 3
Sec. 3.1
– printf(“…fmtStr…”, arg1, arg2, …, argn)
• “… fmtStr…” is a string that can contain conversion specifiers
• the no. of conversion specifiers should be equal to n
• “regular” (non-%) characters in fmtStr written out unchanged
– each conversion specifier is introduced by ‘%’
• this is followed by additional (optional) characters specifying how
wide the output is to be, precision, padding, etc.
• the conversion specifier indicates how the specified value is to be
interpreted:
– d = decimal integer, e.g.: printf(“value = %d\n”, n);
– x = hex integer, e.g.: printf(“hex value of %d is %x\n”, x, x);
– f = floating point number, e.g.: printf(“area = %f\n”, A);
12
Function calls (cont’d)
What happens when this printf()
is called?
• the arguments are evaluated
(as in all C function calls)
• factorial(6) evaluated
• when factorial() returns, the
printf is executed:
• printf(“ … ”, 720)
• This causes the string
factorial(6) = 720
to be printed out
13
Formatted Input: scanf()
• takes a variable no. of arguments:
text: Ch. 3
Sec. 3.2
– scanf(“…fmtStr…”, arg1, arg2, …, argn)
•
•
•
•
“… fmtStr…” is a string that can contain conversion specifiers
the no. of conversion specifiers should be equal to n
argi are locations where values that are read in should be placed
each conversion specifier is introduced by ‘%’
– similar to conversions for printf
• execution behavior:
– uses format string to read in as many input values from
stdin as it can
– return value indicates the no. of values it was able to read
• return value of EOF (-1) indicates no further input (“end of file”).
14
scanf()
• Specifying where to put an input value:
– in general we need to provide a pointer to the location
where the value should be placed
• for a scalar variable X, this is typically written as &X
– Examples:
• scanf(“%d”, &n) : read a decimal value into a variable n
• scanf(“%d %d %d”, &x, &y, &z) : read three decimal values and
put them into variables x, y, z respectively
– suppose the input contains the values 12, 3, 71, 95, 101. Then:
» x  12; y  3; z  71; return value = 3
– suppose the input contains the values 19, 23. Then:
» x  19; y  23; z is unassigned; return value = 2
15
Primitive data types: Java vs. C
• C provides some numeric types not available in Java
– unsigned
• The C language provides only a “minimum size”
guarantee for primitive types
– the actual size may vary across processors and compilers
• Originally C did not have a boolean type
– faked it with ints: 0  false; non-0  true
• hence code of the form:
if ( (x = getnum()) ) { … } // if value read is nonzero
– C99 provides some support for booleans
16
Primitive numeric types: Java vs. C
Java
byte
short
int
?
long
C
C size
unsigned char
typically (and at least) 8 bits
signed char
typically (and at least) 8 bits
char
typically (and at least) 8 bits
unsigned short int
typically (and at least) 16 bits
signed short int
== unsigned short
unsigned int
16 or 32 bits
signed int
same as unsigned int
unsigned long int
typically (and at least) 32 bits
signed long int
== unsigned long
unsigned long long int
typically (and at least) 64 bits
signed long long int
== unsigned long long
Comments
signedness is implementation
dependent
the “natural” size for the machine
Note: the keywords in gray may be omitted
17
Signed vs. unsigned values
• Essential idea:
– “signed” : the highest bit of the value is interpreted as the
sign bit (0 = +ve; 1 = ve)
– “unsigned” : the highest bit not interpreted as sign bit
• For an n-bit value:
– signed: value ranges from 2n-1 to +2n-1 1
– unsigned: value ranges from 0 to 2n1
• Right-shift operator ( >> ) may behave differently
– unsigned values: 0s shifted in on the left
– (signed) negative values: bit shifted in is implementation
dependent
18
Booleans
• Originally, C didn’t have a separate boolean type
– truth values were ints: 0 = false; non-0 = true
– still commonly used in programming
• C99 provides the type _Bool
– _Bool is actually an (unsigned) integer type, but can only
be assigned values 0 or 1, e.g.:
_Bool flag;
flag = 5; /* flag is assigned the value 1 */
• C99 also provides boolean macros in stdbool.h:
#include <stdbool.h>
bool flag; /* same as _Bool flag */
flag = true;
19
Arithmetic operators: Java vs. C
• Most of the common operators in C are as in Java
– e.g.: +, ++, +=, -, -=, *, /, %, >>, <<, &&, ||, …
• C doesn’t have operators relating to objects:
new, instanceof
• C doesn’t have >>> (and >>>=)
– use >> on unsigned type instead
20
Assignment: l-values
increment x twice?
what’s going on?
21
Assignment: l-values
• The left-hand-side (destination) of an assignment has
to be a location
– this is referred to as an “l-value”
• Consider an expression
x ++ ++
the outer “++” operator attempts to increment x++
but x++ is an expression that has no location!
 error
the ++ operator assigns the value x+1 to the location of x
the expression ‘x ++’ has the value of x, but no location
(as a side-effect, x gets incremented)
x has a location and a value
22
What can be an l-value?
• l-values:
– names of variables of arithmetic type (int, char, float, etc.)
– array elements: x[y]
– also:
• structs, unions, pointers, etc. (to be discussed later)
• operations involving pointers (to be discussed later)
• Not l-values:
– names of arrays, functions
– result of an assignment
– value returned by a function call
23
Characters and strings
• A character is of type char (signed or unsigned)
– C99 provides support for “wide characters”
• strings :
– an array of characters
– terminated by a 0 character (“NUL” : written ‘\0’)
– Not a predefined type in C; string operations are provided
through libraries
C arrays don’t do bound-checking
– careless programming can give rise to memory-corruption
errors
24
Example of string manipulation
declares an array of chars
the input analog to printf:
“read a value into str”
(%s = “string”)
print out a string (%s)
25
More strings…
waits for input (from stdin)
typed in on keyboard: stdin
program output (stdout)
end-of-file indicated by typing Ctrl-D
26
More strings…
Oops!
this means the program tried
to access an illegal memory
address
27
Functions from special libraries
• Some library code is not linked in by default
– Examples: sqrt, ceil, sin, cos, tan, log, … [math library]
– requires specifying to the compiler/linker that the math
library needs to be linked in
• you do this by adding “lm” at the end of the compiler invocation:
gcc Wall foo.c lm
linker command to
add math library
• Libraries that need to be linked in explicitly like this
are indicated in the man pages
28
Bit Operations
• C provides operations to manipulate individual bits
of values
– done properly and in the right places, this can lead to
elegant and efficient code
– no. of bits per byte may vary across architectures:
the macro CHAR_BIT (defined via #include <limits.h>)
gives the no. of bits in a byte.
29
Bit Operations
Operation
Operator
Bitwise complement (unary)
~
Bitwise shift
>> <<
Bitwise AND
&
Bitwise XOR
^
Bitwise OR
|
precedence
high
low
30
Bit Masks
• We can select (look at, define) specific bits of a value
using bit masks (a fixed bit pattern). E.g.:
– for least significant bit in a byte: 0x1
– for most significant bit in a byte: (0x1 << (CHAR_BIT–1))
• More generally: let
MASK = 0 … 0i+1 1i 0i-1 … 00
then, for a value x:
i
only bit i of x:
(x & MASK)
x with bit i set to 1: (x | MASK)
x with bit i set to 0: (x & ~MASK)
31
Example Use: Representing Fixed-size Sets
• Intuition:
– each distinct element that can be in the set is assigned a
bit position
– suppose x is a variable that holds such a set, and p is an
element whose assigned position is k. Then:
•
•
•
•
•
to add p to x: x = x | (1 << k)
to check whether x is in p: evaluate x & (1 << k)
set union: bitwise or, |
set intersection: bitwise and, &
set complement: bitwise negation, ~
• But what if the size of the set is too big for an int?
32
Representing Fixed-size Sets
• To handle sets that may be too large to
represent using a single word (e.g., int):
– each element still gets assigned a fixed
position k
(now k may be larger than 32 or 64)
– use an array of ints (or longs) to represent
the set
– use a 2-level mapping to map the position k
to a bit position in this array:
1
• first figure out which array element we need
• then figure out which bit position in this array we
need
33
Representing Fixed-Size Sets: Example
• Suppose we have:
– a set that can contain upto 350 elements
– an int holds 32 bits
– an element p corresponds to position 212 in the set
• Then:
– use an array of 11 ints to represent the set
(11 x 32 = 352)
– p is in element 7 of this array (e.g., A[7])
(element 7 holds positions 192–223)
– within element 7 of the array, p is at bit position 20.
34
Download