Skip to content
VLSI Mentor

C Part I · Module 3 · Expressions and Operators

Comparison Operators

Chapter 3.4 gave you a way to change an object. This chapter gives you a way to ask a question about values — whether one is larger, whether two are the same — and the answers turn out to be ordinary numbers rather than anything special. That is worth knowing precisely, because C's comparison operators produce an int, not a dedicated truth type, and the difference explains behaviour you will meet repeatedly. The chapter then does the thing that makes it one of the more important in the module: it returns to the comparison Chapter 2.6 showed you, where −1 is reported as not less than 1, and replaces the observation with a rule you can apply and a reason you can state.

Foundation12 min readCPart IFundamentalsExpressions

Part I · Module 3 · Chapter 3.5 · Comparison Operators

1. Asking a Question About Two Values

C has six operators for comparing values. Four compare magnitude and two compare for sameness:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  a <  b      is a less than b?
  a <= b      is a less than or equal to b?
  a >  b      is a greater than b?
  a >= b      is a greater than or equal to b?

  a == b      are a and b equal?
  a != b      are a and b different?

Each is an operator with two operands, so each forms an expression — and Chapter 3.1's two questions apply to it as they do to everything else. What value does it produce, and what type?

2. The Answer Is an Ordinary Number

Azvya Education Pvt. Ltd.VLSI Mentor
what comparisons produce
#include <stdio.h>

int main(void)
{
    printf("4 < 7  is %d\n", 4 < 7);
    printf("4 > 7  is %d\n", 4 > 7);
    printf("4 == 7 is %d\n", 4 == 7);
    printf("4 != 7 is %d\n", 4 != 7);
    printf("4 <= 4 is %d\n", 4 <= 4);
    return 0;
}

Output:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
4 < 7  is 1
4 > 7  is 0
4 == 7 is 0
4 != 7 is 1
4 <= 4 is 1

Note the %d in every line. That is not a trick — it works because of the precise answer to Chapter 3.1's second question:

A comparison produces an int, with the value 1 if the comparison holds and 0 if it does not.

Not a bool. Not a special truth object. An int, which you can print with %d, store in an int, or use in arithmetic. Chapter 2.10 established why: C's truth model — zero is false, anything else is true — predates its bool type by decades, and comparisons were producing plain integers long before there was anything else for them to produce.

You can store the result like any other value:

Azvya Education Pvt. Ltd.VLSI Mentor
a comparison stored
#include <stdio.h>

int main(void)
{
    int temperature = 30;
    int limit = 25;
    int too_hot = temperature > limit;

    printf("too_hot is %d\n", too_hot);
    return 0;
}

Output:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
too_hot is 1

too_hot is an ordinary int holding 1. If you would rather the object say what it means, declare it bool instead — Chapter 2.10 explained what that changes and what it does not.

3. = and == Are Different Operators

Chapter 3.4 introduced = and deliberately withheld == until now, because the two are easily confused and the confusion is expensive.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  =     store the right-hand value into the left-hand object
  ==    ask whether two values are equal

Different jobs, and only one of them changes anything. What makes this dangerous is that writing the wrong one is frequently still valid C:

Azvya Education Pvt. Ltd.VLSI Mentor
a slip that compiles
#include <stdio.h>

int main(void)
{
    int value = 3;
    int check = (value = 5);

    printf("check is %d, value is now %d\n", check, value);
    return 0;
}

Output:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
check is 5, value is now 5

The author almost certainly meant value == 5 — is value equal to 5? — which would have produced 0, because value held 3. Instead the line stored 5 into value and produced 5, so check is 5 and the object has been changed as a side effect.

Nothing here is a C error. The compiler accepted it because Chapter 3.4 established that an assignment is an expression with a value, and this is a perfectly ordinary use of one.

4. The Comparison That Reports the Opposite

Chapter 2.6 showed you a comparison whose result contradicts the code. Here it is again, now with a companion line that isolates the cause:

Azvya Education Pvt. Ltd.VLSI Mentor
the same numbers, two different answers
#include <stdio.h>

int main(void)
{
    int signed_count = -1;
    unsigned int unsigned_limit = 1;

    printf("-1 < 1 as written : %d\n", signed_count < unsigned_limit);
    printf("-1 < 1 both signed: %d\n", -1 < 1);
    return 0;
}

Output:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
-1 < 1 as written : 0
-1 < 1 both signed: 1

The second line is what arithmetic says: −1 is less than 1. The first line uses the same two numbers and reports the opposite.

The difference is the type of the second operand, and here is the rule:

When a comparison has one signed operand and one unsigned operand of the same width, C converts the signed value to the unsigned type before comparing.

So the first comparison never asks is −1 less than 1. By the time the comparison happens, the −1 has been converted, and Chapter 2.7 told you what that conversion produces: the bit pattern of −1 read as unsigned is the largest value the type can hold. The comparison being performed is therefore is 4294967295 less than 1, and the answer to that is correctly 0.

Nothing malfunctioned. The operands were changed before the operator saw them, and the operator then did its job properly on values you did not write.

This is why Chapter 3.1 asked you to get into the habit of asking about the type of every expression, not just its value. The value here is entirely explained by the types.

Your compiler will warn if you ask it to:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
warning: comparison of integers of different signs: 'int' and 'unsigned int' [-Wsign-compare]

which is another entry in the list of reasons the options from Chapter 1.5 are not optional. Wording differs between compilers; the category is what to recognise.

5. Practical Guidance

Three things follow, and they are worth adopting as habits rather than remembered as rules.

Avoid comparing signed with unsigned. If both values are quantities, make them both signed — which is Chapter 2.6's default advice, and §4 is a large part of why. When you genuinely must compare across signedness, be explicit about what you want; Chapter 3.12 gives you the tool.

Comparing floating-point values for equality needs care. Chapter 2.9 covered this in full: == is reliable for exactly representable values and unreliable for anything computed from decimal fractions. The operator is not the problem; the values are.

Comparing a truth value against 1 is a mistake. From §2: a true value need not be 1. Compare against 0 if you must compare at all — x != 0 is always meaningful, x == 1 frequently is not.

6. What You Should Be Able to Say Now

  1. C has six comparison operators: <, <=, >, >=, ==, !=.
  2. A comparison produces an int — 1 if it holds, 0 if it does not. Not a bool, not a special type.
  3. That result can be printed with %d, stored in an int, or stored in a bool if you prefer the intent stated.
  4. A true value need not be 1, which is why comparing against 1 is unsafe and comparing against 0 is not.
  5. = stores; == asks. Writing one for the other is often still valid C and changes an object as a side effect.
  6. Compilers warn about the slip only in some positions, and extra parentheses suppress the warning.
  7. Mixing signed and unsigned converts the signed operand first, which is why -1 < 1u is 0 while -1 < 1 is 1.
  8. Nothing is broken there: the operands were converted before the operator ran.
  9. -Wsign-compare catches it. Prefer not to mix signedness at all.

7. Exercise

Exercise 1 — predict, then run. Give the exact output:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
printf("%d\n", 10 >= 10);
printf("%d\n", 10 != 10);
printf("%d\n", 3 < 2);
printf("%d\n", (2 < 3) + (4 < 5));

The last line is deliberate — explain why it is legal.

Exercise 2 — say what changed. For each, say what is printed and whether any object was modified:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
int n = 4;
printf("%d\n", n == 6);
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
int n = 4;
printf("%d\n", n = 6);

Exercise 3 — explain the reversal. Write two sentences explaining why signed_count < unsigned_limit gave 0 in §4. Your explanation must mention conversion and must not use the word "bug".

Exercise 4 — predict the warning. Which of these does -Wsign-compare complain about, and why does it not complain about the others?

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
int a = -1;
unsigned int b = 1;
int c = 2;

a < b;
a < c;
b < b;

Exercise 5 — repair it. A function-free program tracks int remaining and compares it against an unsigned int capacity. Describe the failure that can occur when remaining is negative, and give the simplest change that removes the risk entirely.

Exercise 6 — judge the comparison. For each, say whether == is a reasonable thing to write, referring to Chapter 2.9 where relevant: two int values; two double values computed from decimal fractions; a double compared against 0.5; a truth value compared against 1.

8. Summary

  • Six comparison operators, four about magnitude and two about sameness.
  • Each produces an int — 1 or 0 — because C's truth model predates its bool type.
  • True does not mean 1. Any non-zero value is true, so compare against 0, never against 1.
  • = stores, == asks. The slip is usually valid C, changes an object, and is only sometimes warned about.
  • Signed meets unsigned and the signed operand is converted first, which is the whole explanation for -1 < 1u being 0.
  • The operator did its job correctly on values you did not write. That is the pattern, and Chapter 3.12 gives the general rules.
  • Do not mix signedness in comparisons, and treat floating-point equality as Chapter 2.9 described.

You can now ask a single question about two values. Real programs ask several at once — this and that, this or that — and C's operators for combining questions have a property that makes them different from every operator you have met so far: sometimes they do not evaluate one of their operands at all.

Standards & specifications

Governing standard
ISO/IEC 9899 (the C language standard)(opens ISO/IEC (JTC 1/SC 22/WG 14) in a new tab)

Defines the C language itself — the type system, expression semantics, object model, storage duration and the behaviour categories a conforming implementation must honour. It is a FAMILY of editions (C89/C90, C99, C11, C17, C23) and this curriculum names the edition wherever a claim depends on one. It does not define any foreign-function interface to a hardware description language, and it does not define platform behaviour: what a memory-mapped access does on real silicon is the implementation's and the device's contract, not this standard's. Working drafts published by WG14 are freely available and are what most engineers read day to day; a draft is not the published standard.

This page also covers RTL structure, verification approach and debugging technique. Those are engineering practice built on the standard, not requirements the standard itself imposes.

Where this fits

Part of the C Programming curriculum.