1. Homepage of Dr. Zoltán Porkoláb
    1. Home
    2. Archive
  2. Teaching
    1. Timetable
    2. Multiparadigm programming (MSc)
    3. C programming (BSc for physicists)
    4. Project tools (BSc)
    5. Bolyai College
    6. C++ (for foreign studenst)
    7. Software technology lab
    8. BSc and MSc thesis
  3. Research
    1. Templight
    2. CodeChecker
    3. CodeCompass
    4. Projects
    5. Publications (up to 2011)
    6. PhD students
  4. Affiliations
    1. Dept. of Programming Languages and Compilers
    2. Ericsson Hungary Ltd

The C programming language – Lecture 4.

Operators, Expressions, Expression evaluation

Expressions are formed from operators and values or variables. The most simple expressions are similar to the mathematical expressions.

A + B * C

What is the meaning?

A + (B * C)

Because the precedence of multiplication is higher/stronger than the addition.

What happens, when the operators are on the same precedence level?

A * B / C * D

In FORTRAN77, it was not defined, what is the meaning of this expression:

((A * B) / C) * D
(A * B * D) / C
(A / C) * B * D

…and if A, B, C, D are INTEGERs, the final result could be different.

In modern languages, expressions are defined by precedence and associativity rules.

In some languages, like Java, associativity always left-to-right. In C associativity is defined by precedence rules. In most precedence groups it is left-to-right, but for unary, ternary and assignment operators they are right-to-left.

Operators in C

Precedence Operator Description Assoc
Postfix ++ postfix increment L->R
  – – postfix decrement  
  () function call  
  [] array index  
  . struct/union member access  
  -> member access via pointer  
  (type){list} compound literal (C99)  
Unary ++ prefix increment R->L
  – – prefix decrement  
  + unary plus  
  unary minus  
  ! logical negation  
  ~ binary negation  
  (type) type conversion  
  * pointer indirection  
  & address of  
  sizeof size of type/object  
  _Alignof alignment requirement (C11)  
Multiplicative * / % multiplication, division, remainder L->R
Additive + – addition, substraction L->R
Shift « » bitwise left/right shift L->R
Relational < <= > >= relational operations L->R
Equality == != equal, not equal L->R
Bitwise & bitwise AND L->R
  ^ bitwise XOR (exclusive OR) L->R
  | bitwise OR L->R
Logical && logical AND L->R
  || logical OR L->R
Ternary ? : conditional expression R->L
Assignment = assignment R->L
  += –= compound assignment  
  *= /= %=    
  «= »=    
  &= |= ^=    
Comma , sequence operator L->R

Evaluation of expressions

Although, expressions are defined by precedence and associativity, how the expression is evaluated is implementation defined.

What will print the following program?

1
2
3
4
5
6
7
#include <stdio.h>
int main()
{
  int i = 1;
  printf( "i = %d, ++i = %d\n", i, ++i );
  return 0;
}
$ ./a.out 
i = 2, ++i = 2

The evaluation order is usually not defined for expressions.

Exceptions are those operations which are sequence points

  1. shortcut logical operators ( && || )
  2. conditional operator ( ? : )
  3. comma operator

Also, when a function is called, first the operands are evaluated, (but in undefined order)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <stdio.h>
int f()
{
  printf("f\n");
  return 2;
}
int g()
{
  printf("g\n");
  return 1;
}
int f()
{
  printf("h\n");
  return 0;
}
void func()
{
  printf("(f() == g() == h()) == %d", f() == g() == h());
}
int main()
{
  func();
  return 0;
}
$ gcc -ansi -pedantic -Wall f.c
f.c: In function ‘func’:
f.c:20:44: warning: suggest parentheses around comparison in operand of ‘==[-Wparentheses]
printf("func: (f() == g() == h()) == %d", fpar == gpar == hpar);
                                               ^
$ ./a.out 
h
g
f
func: (f() == g() == h()) == 1
$

Common errors

Wrong precedence

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/*
 * LIKELY BAD!
 */
#include <stdio.h>
int main()
{
  int mask = 0x01;
  if ( mask & 0x10 == 16 )
  {
     printf("This is strange!\n");
  }
  printf("mask = %d, 0x10 = %d,  mask & 0x10 = %d,  mask & 0x10  == 16 = %d\n",
          mask,      0x10,       mask & 0x10,       mask & 0x10  == 16);
  return 0;
}
$ gcc -ansi -pedantic -Wall -W  f.c
f.c: In function ‘main’:
f.c:6:13: warning: suggest parentheses around comparison in operand of ‘&’ [-Wparentheses]
   if ( mask & 0x10 == 16 )
             ^
f.c:11:58: warning: suggest parentheses around comparison in operand of ‘&’ [-Wparentheses]
           mask,      0x10,       mask & 0x10,       mask & 0x10  == 16);
                                                          ^
$ ./a.out
This is strange!
mask = 1, 0x10 = 16,  mask & 0x10 = 0,  mask & 0x10  == 16 = 1
$

Correct way

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/*
 * OK!
 */
#include <stdio.h>
int main()
{
  int mask = 0x01;
  if ( (mask & 0x10) == 16 )
  {
     printf("This is strange!\n");
  }
  printf("mask = %d, 0x10 = %d, (mask & 0x10) = %d, (mask & 0x10) == 16 = %d\n",
          mask,      0x10,       mask & 0x10,       (mask & 0x10) == 16);
  return 0;
}
$ gcc -ansi -pedantic -Wall -W  f.c
gsd@Kubuntu-e1:~/ftp$ ./a.out 
mask = 1, 0x10 = 16, (mask & 0x10) = 0, (mask & 0x10) == 16 = 0

Assignment vs equality check

1
2
3
4
5
6
7
8
9
10
11
12
13
/*
 * BAD!
 */
#include <stdio.h>
int main()
{
  int i = 0;
  if ( i = 1 )
  {
    printf("This is strange!\n");
  }
  return 0;
}
$ gcc -ansi -pedantic -Wall -W  f.c
f.c: In function ‘main’:
f.c:6:3: warning: suggest parentheses around assignment used as truth value [-Wparentheses]
  if ( i = 1 )
  ^
$ ./a.out 
This is strange!

The safe way

1
2
3
4
5
6
7
8
9
10
#include <stdio.h>
int main()
{
  int i = 0;
  if ( 1 = i )
  {
    printf("This is strange!\n");
  }
  return 0;
}
$ gcc -ansi -pedantic -Wall -W  f.c
f.c: In function ‘main’:
f.c:6:10: error: lvalue required as left operand of assignment
   if ( 1 = i )
          ^

Missing sequence point

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/*
 * BAD!
 */
#include <stdio.h>
int main()
{
  int t[10];
  int i = 0;
  while( i < 10 )
  {
    t[i] = i++;
  }
  for ( i = 0; i < 10; ++i )
  {
    printf("%d ", t[i]);
  }
  return 0;
}
$ gcc -ansi -pedantic -Wall -W  f.c
f.c: In function ‘main’:
f.c:9:13: warning: operation on ‘i’ may be undefined [-Wsequence-point]
   t[i] = i++;
           ^
$ ./a.out 
613478496 0 1 2 3 4 5 6 7 8 
$

Correct way

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/*
 * OK
 */
#include <stdio.h>
int main()
{
  int t[10];
  int i = 0;
  while( i < 10 )
  {
    t[i] = i;
    ++i;
  }
  for ( i = 0; i < 10; ++i )
  {
    printf("%d ", t[i]);
  }
  return 0;
}