Need Help or More Information?
Questions about this free C programming course, embedded C training or career guidance? Get in touch.
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.
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
ifstatements - The difference between
=and==and how GCC helps you catch it - Why
10 < x < 50is not a range test - Safe floating-point and signed/unsigned comparisons
- Where relational operators sit in operator precedence
Key Terms in This Lecture
Prerequisites
Before you start
- Variables,
intandprintffrom earlier lectures. - The idea of an
ifstatement (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
| Operator | Meaning | Example (a = 9, b = 5) | Value |
|---|---|---|---|
< | less than | a < b | 0 |
<= | less than or equal to | a <= b | 0 |
== | equal to | a == b | 0 |
!= | not equal to | a != b | 1 |
> | greater than | a > b | 1 |
>= | greater than or equal to | a >= b | 1 |
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
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 = bfails 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) | Operators | Example effect |
|---|---|---|
| 1 | Arithmetic + - * / % | Done first |
| 2 | Relational < <= > >= | a + b > c means (a + b) > c |
| 3 | Equality == != | a < b == c means (a < b) == c |
| 4 | Logical && then || | Combine comparisons |
| 5 | Assignment = and compound forms | Done 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
| Mistake | What you see | Fix |
|---|---|---|
if (a = b) | Condition always true if b is non-zero; a overwritten | Use == |
10 < x < 50 | Always true or surprising | Write 10 < x && x < 50 |
f1 == f2 on floats | False although values look equal | Compare fabs(f1 - f2) with a tolerance |
| Signed vs unsigned compare | -1 appears larger than 1 | Cast or use matching types |
Comparing strings with == | Compares addresses, not text | Use strcmp |
Missing scanf check | Comparing uninitialised values | Test the return value |
Best Practices, Performance and Security
- Prefer parentheses around mixed expressions, for example
(a > b) == (c > d). - Compile with
-Wall -Wextraand 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 < cis 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