What are C Relational Operators Explained- Embedded C Programming Course

Need Help or More Information?

Questions about this free C programming course, embedded C training or career guidance? Get in touch.

Free C Programming Course • Chapter 4 • Lecture 6

C Relational Operators Explained

Learn the six relational operators in C, why they return 1 or 0, and the famous traps: = versus ==, chained comparisons, float equality and signed versus unsigned. A free C tutorial for embedded C programming.

6
Relational operators
7
Runnable programs
6
Classic traps explained

This lecture continues our free C programming course with the operators that let your program ask questions. Relational operators compare two values and answer with 1 or 0, and they sit behind every decision in the code you will write.

In this free C tutorial you will run real examples, read real compiler warnings and meet the bugs that interviewers like to ask about. Everything is explained for beginners but with the depth needed for embedded C programming.

What You Will Learn

  • The six relational operators and what each one means
  • Why a comparison gives the integer 1 or 0
  • Using comparisons inside if statements
  • The difference between = and == and how GCC helps you catch it
  • Why 10 < x < 50 is not a range test
  • Safe floating-point and signed/unsigned comparisons
  • Where relational operators sit in operator precedence

Key Terms in This Lecture

relational operator equality operator true and false condition == vs = tolerance sign conversion precedence embedded C programming free C tutorial

Prerequisites

Before you start

  • Variables, int and printf from earlier lectures.
  • The idea of an if statement (a quick preview is enough).
  • GCC installed so you can run the examples.

Why Comparisons Matter in a Free C Programming Course

A program that cannot compare two values cannot make a decision. Every if, every while and every for loop depends on a question that has a yes-or-no answer: is the temperature too high, did the counter reach its limit, has the user typed the right code? C answers those questions with the relational operators. They are the bridge between raw numbers and program flow, which makes them essential in any free C programming course and in every embedded C programming project, from a blinking LED to a motor controller.

A relational operator looks at the values of two expressions and reports how they relate. An expression that contains one is called a relational expression. If the relation holds, the whole expression has the value 1. If it does not hold, the value is 0. That is all there is to it, and yet this tiny rule hides several interesting traps that we will walk through with real compiler output.

The Six Relational Operators in Our Free C Programming Course

OperatorMeaningExample (a = 9, b = 5)Value
<less thana < b0
<=less than or equal toa <= b0
==equal toa == b0
!=not equal toa != b1
>greater thana > b1
>=greater than or equal toa >= b1

Strictly speaking the standard puts == and != in a separate group called equality operators, and <, <=, >, >= in the relational group. In everyday teaching we treat all six together because they all answer a comparison question. The difference matters only for precedence, which we cover shortly.

How a relational expression is evaluated

Left operand: a = 9→Operator: >→Right operand: b = 5
Relation true?→Yes: value is 1→No: value is 0

Important: the result is an ordinary int

C has no separate true/false value for these results. A comparison gives the integer 1 or 0, so you can print it with %d, add it to another number, or store it in an int. In C99 and later <stdbool.h> offers bool, but the comparison itself still has type int.

Example 1: A Table of Relational Results

Let us ask the compiler to tell us the value of ten different relational expressions:

#include <stdio.h>

int main(void)
{
    int a = 9, b = 5;

    printf("a = %d, b = %d\n", a, b);
    printf("a <  b  -> %d\n", a < b);
    printf("a <= b  -> %d\n", a <= b);
    printf("a == b  -> %d\n", a == b);
    printf("a != b  -> %d\n", a != b);
    printf("a >  b  -> %d\n", a > b);
    printf("a >= b  -> %d\n", a >= b);
    printf("a == 0  -> %d\n", a == 0);
    printf("b != 0  -> %d\n", b != 0);
    printf("a >  8  -> %d\n", a > 8);
    printf("2 >  4  -> %d\n", 2 > 4);
    return 0;
}
gcc -std=c11 -Wall -Wextra -o ep_rel_table ep_rel_table.c
./ep_rel_table

Expected output:

a = 9, b = 5
a <  b  -> 0
a <= b  -> 0
a == b  -> 0
a != b  -> 1
a >  b  -> 1
a >= b  -> 1
a == 0  -> 0
b != 0  -> 1
a >  8  -> 1
2 >  4  -> 0

Check a few by hand. a > 8 is true because 9 is greater than 8, so it prints 1. 2 > 4 is false, so it prints 0. Notice that the operands do not have to be variables: constants and whole expressions are fine on either side.

Using Relational Operators with if Statements

Relational expressions are normally used inside if conditions and loop tests. The if statement evaluates its condition. If the value is non-zero (true) the next statement runs; if it is zero the next statement is skipped. The full story of if comes in the next chapter, but you already have enough to see the operators at work.

Example 2: Compare Two Numbers Typed by the User

#include <stdio.h>

int main(void)
{
    int a, b;

    printf("Enter two integers: ");
    if (scanf("%d %d", &a, &b) != 2) {
        printf("Need two integers\n");
        return 1;
    }
    if (a < b)  printf("%d is less than %d\n", a, b);
    if (a <= b) printf("%d is less than or equal to %d\n", a, b);
    if (a == b) printf("%d is equal to %d\n", a, b);
    if (a != b) printf("%d is not equal to %d\n", a, b);
    if (a > b)  printf("%d is greater than %d\n", a, b);
    if (a >= b) printf("%d is greater than or equal to %d\n", a, b);
    return 0;
}
gcc -std=c11 -Wall -Wextra -o ep_compare ep_compare.c
./ep_compare

Sample run with the inputs 12 and 7:

Enter two integers: 12 7
12 is not equal to 7
12 is greater than 7
12 is greater than or equal to 7

Sample run with equal inputs 5 and 5:

Enter two integers: 5 5
5 is less than or equal to 5
5 is equal to 5
5 is greater than or equal to 5

With 5 and 5 three lines print: equal, less-than-or-equal and greater-than-or-equal, because all three relations are true at once. Several conditions can be true for the same pair of numbers, and that is perfectly normal. Also notice we check the return value of scanf: it reports how many values were read, so we do not compare garbage if the user types letters.

Equality vs Assignment: Free C Programming Course Bug Hunt

The assignment operator = stores a value. The equality operator == compares two values. They look almost the same, beginners mix them up, and the resulting bug is hard to see because the program compiles and runs.

#include <stdio.h>

int main(void)
{
    int a = 12, b = 7;

    if (a = b)
        printf("%d is equal to %d ?!\n", a, b);
    printf("a is now %d\n", a);
    return 0;
}

Here GCC at least gives us a hint:

ep_assign_bug.c: In function ‘main’:
ep_assign_bug.c:7:9: warning: suggest parentheses around assignment used as truth value [-Wparentheses]
    7 |     if (a = b)
      |         ^

Output when you run it:

7 is equal to 7 ?!
a is now 7

What happened? a = b is an assignment expression. It copies 7 into a and its own value is the value that was assigned, 7. Seven is non-zero, so the condition is true and the message prints, even though a and b started out different. Worse, a has been silently overwritten.

Two habits that prevent this bug

  • Always compile with -Wall; it warns about assignment used as a condition.
  • Some teams write constants on the left: if (7 == b). If you accidentally type =, 7 = b fails to compile. Use this style only if your team agrees on it.

Chained Comparisons Do Not Work Like Maths

In school you write 10 < t < 50 to mean “t is between 10 and 50”. In C the same text compiles but does not mean that. The comparison is evaluated left to right, so 10 < t is computed first, giving 0 or 1, and that result is then compared with 50.

#include <stdio.h>

int main(void)
{
    int temp = 95;

    if (10 < temp < 50)
        printf("chained test says %d is in range\n", temp);
    if (10 < temp && temp < 50)
        printf("correct test says %d is in range\n", temp);
    printf("10 < temp         = %d\n", 10 < temp);
    printf("(10 < temp) < 50  = %d\n", (10 < temp) < 50);
    return 0;
}

GCC knows this is almost certainly a mistake:

ep_chain.c: In function ‘main’:
ep_chain.c:7:19: warning: comparison of constant ‘50’ with boolean expression is always true [-Wbool-compare]
    7 |     if (10 < temp < 50)
      |                   ^
ep_chain.c:7:12: warning: comparisons like ‘X<=Y<=Z’ do not have their mathematical meaning [-Wparentheses]
    7 |     if (10 < temp < 50)
      |         ~~~^~~~~~
ep_chain.c:12:52: warning: comparison of constant ‘50’ with boolean expression is always true [-Wbool-compare]
   12 |     printf("(10 < temp) < 50  = %d\n", (10 < temp) < 50);
      |                                                    ^

Output:

chained test says 95 is in range
10 < temp         = 1
(10 < temp) < 50  = 1

With temp = 95 the chained test claims 95 is in range because (10 < 95) is 1 and 1 < 50 is true. The correct version, 10 < temp && temp < 50, correctly rejects it. Always join two comparisons with the logical AND operator, which you will study in the next lecture.

Comparing Floating-Point Numbers Safely

Floating-point values are stored in binary and many decimal fractions cannot be represented exactly. Comparing them with == can fail even when the maths says the values are equal.

#include <stdio.h>
#include <math.h>

int main(void)
{
    double a = 0.1 + 0.2;
    double b = 0.3;

    printf("a == b            : %d\n", a == b);
    printf("a printed (%%.17g): %.17g\n", a);
    printf("fabs(a-b) < 1e-9  : %d\n", fabs(a - b) < 1e-9);
    return 0;
}
gcc -std=c11 -Wall -Wextra -o ep_float_cmp ep_float_cmp.c -lm
./ep_float_cmp
a == b            : 0
a printed (%.17g): 0.30000000000000004
fabs(a-b) < 1e-9  : 1

The sum of 0.1 and 0.2 is stored as 0.30000000000000004, not exactly 0.3. The fix is to test whether the difference is smaller than a small tolerance. Pick a tolerance that suits your data; the 1e-9 above is just an example. On some systems you need -lm so the linker finds the math library for fabs.

Signed vs Unsigned Trap

When you compare a signed number with an unsigned one, C converts the signed value to unsigned first. A negative number then becomes a huge positive one.

#include <stdio.h>

int main(void)
{
    int      level = -1;
    unsigned limit = 1;

    if (level < limit)
        printf("-1 < 1u is true\n");
    else
        printf("-1 < 1u is false\n");
    printf("(unsigned)-1 = %u\n", (unsigned)level);
    return 0;
}
ep_sign.c: In function ‘main’:
ep_sign.c:8:15: warning: comparison of integer expressions of different signedness: ‘int’ and ‘unsigned int’ [-Wsign-compare]
    8 |     if (level < limit)
      |               ^
-1 < 1u is false
(unsigned)-1 = 4294967295

-1 < 1u is false, because -1 turned into 4294967295 before the comparison. This shows up in embedded code whenever a signed sensor delta is compared with an unsigned length or timer value. Keep both sides the same signedness, or cast deliberately.

Precedence and Where Comparisons Fit

Priority (high to low)OperatorsExample effect
1Arithmetic + - * / %Done first
2Relational < <= > >=a + b > c means (a + b) > c
3Equality == !=a < b == c means (a < b) == c
4Logical && then ||Combine comparisons
5Assignment = and compound formsDone last

You rarely need extra parentheses around arithmetic inside a comparison, but you should add them when you mix several kinds of operators. They cost nothing and make the code readable.

Common Mistakes and Troubleshooting

MistakeWhat you seeFix
if (a = b)Condition always true if b is non-zero; a overwrittenUse ==
10 < x < 50Always true or surprisingWrite 10 < x && x < 50
f1 == f2 on floatsFalse although values look equalCompare fabs(f1 - f2) with a tolerance
Signed vs unsigned compare-1 appears larger than 1Cast or use matching types
Comparing strings with ==Compares addresses, not textUse strcmp
Missing scanf checkComparing uninitialised valuesTest the return value

Best Practices, Performance and Security

  • Prefer parentheses around mixed expressions, for example (a > b) == (c > d).
  • Compile with -Wall -Wextra and treat sign-compare and parentheses warnings as bugs.
  • In embedded C programming compare against named constants (TEMP_MAX) instead of magic numbers.
  • Comparisons are a single instruction on most CPUs and cost almost nothing, so favour clarity over tricks.
  • In safety code, validate lengths and indexes with < against the buffer size before every access to avoid overflows.
  • Never compare floating-point values for exact equality when they come from calculations or sensors.

Real-world uses you will meet

  • Checking an ADC reading against a threshold before turning a fan on.
  • Stopping a loop when a counter reaches a buffer size.
  • Validating that a received length is not larger than the storage you have.
  • Comparing timestamps to decide whether a timeout expired.

Summary and Key Takeaways

  • Relational operators: <, <=, >, >=, ==, !=.
  • A true comparison has the value 1 and a false one the value 0, both of type int.
  • = assigns and == compares; mixing them up is the classic C bug.
  • a < b < c is not a range test; use &&.
  • Do not compare floats with ==; use a tolerance.
  • Signed-versus-unsigned comparisons convert the signed side first.

Conclusion

Comparisons look trivial, but they hold more traps than almost any other part of C. If you can predict each of the outputs in this lecture before running the code, you have the mindset that firmware reviewers look for. In the next lecture of this free C tutorial we combine comparisons with the logical operators, starting with AND, so you can write real conditions such as “the temperature is above 10 and below 50”.

Practice Quiz: Relational Operators

Q1. With int a = 9, b = 5; what is (a > b) + (a > 8) + (b > 8)?

Show answer

2. The terms are 1, 1 and 0.

Q2. What is the value of a - b > 3 for the same values?

Show answer

1. The subtraction happens first (4), then 4 > 3 is true.

Q3. What does 3 > 2 > 1 evaluate to?

Show answer

0. 3 > 2 is 1, and then 1 > 1 is false.

Q4. What does 5 == 5.0 give?

Show answer

1. The integer is converted to double and the two values are equal.

Q5. What does 'a' < 'b' give on an ASCII system?

Show answer

1. The character codes are 97 and 98.

Q6. What happens when you run int x = 3; if (x = 0) printf("zero");?

Show answer

Nothing prints and x becomes 0. The assignment evaluates to 0, which is false.

Q7. What does -1 < 1u print as a true/false result?

Show answer

False (0). The -1 is converted to unsigned 4294967295 before the comparison.

Q8. Does 0.1 + 0.2 == 0.3 hold for IEEE-754 doubles?

Show answer

No, it evaluates to 0 because the sum is slightly larger than 0.3.

Interview Questions on Relational Operators

Q1. What type and values does a relational expression have in C?

Show answer

It has type int and the value 1 for true or 0 for false.

Q2. What is the difference between = and ==?

Show answer

= assigns a value and evaluates to the assigned value; == compares two values and evaluates to 1 or 0.

Q3. Why does if (10 < x < 50) not check a range?

Show answer

It is parsed as (10 < x) < 50. The first comparison gives 0 or 1, which is always less than 50.

Q4. Why should you avoid == with floating-point numbers?

Show answer

Many decimal fractions cannot be stored exactly in binary, so results differ slightly. Compare with a tolerance.

Q5. What is the signed/unsigned comparison pitfall?

Show answer

The signed operand is converted to unsigned, so negative numbers become large positive values and the comparison gives the wrong answer.

Q6. How do you compare two strings in C?

Show answer

Use strcmp. Using == compares pointers, not contents.

Frequently Asked Questions About Relational Operators in C

What are the relational operators in C?

The six operators <, <=, >, >=, == and != compare two values and give 1 for true or 0 for false.

What does a relational expression return in C?

An int equal to 1 when the relation holds and 0 when it does not.

Why does if (a = b) always run?

Because a = b assigns and evaluates to the new value of a. Any non-zero value counts as true.

How do I check that a number is between two limits in C?

Write both comparisons and join them with AND: if (x > 10 && x < 50).

Can I compare floats with == in C?

You can, but it often fails because of rounding. Compare the absolute difference with a small tolerance instead.

Is this a free C tutorial for embedded systems students?

Yes. EmbeddedPathashala offers a free C programming course with compiled examples, quizzes and interview questions focused on embedded C programming.

Where can I find a free embedded C course?

This series is a free embedded C course: every lecture builds toward the C skills needed for microcontroller firmware.

Next: Logical AND in C

Continue the free C programming course with logical operators. You will learn how AND combines conditions, how short-circuit evaluation works, and why it protects your code from crashes.

Need Help or More Information?

Questions about this free C programming course, embedded C training or career guidance? Get in touch.

2 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *