Source: https://mokxi.com/learn/arduino-const-vs-define
Updated: 2026-10-25

Learn

# Arduino const and #define: two ways to name a number

Written by the Mokxi team, updated October 25, 2026

Start building free

Or see every lesson.

- 455 parts on the bench
- 43 boards running now
- 1.00x real time, on every board

Press Run, then change LAMP to 12

const int LAMP = 13; names the pin once. Change it to 12 and the yellow lamp blinks instead.

Both give a number a name, so you can write LAMP instead of 13 and change it in one place. const int LAMP = 13; makes a variable with a type that can never change. #define LAMP 13 tells the compiler to find every LAMP in the sketch and paste 13 in its place before it compiles anything. For pin numbers and settings, use const: the Arduino reference recommends it, and it avoids every mistake below.

The circuit above is the code bench, an Uno with three lamps. Press Run. The red lamp on pin 13 blinks, and the serial monitor prints "hello from the board", "setup() has run once" and then "loop() pass 1", "loop() pass 2" and so on. The pin is named once, at the top, as const int LAMP = 13;. Change the 13 to 12, press Run, and pin 12, the yellow lamp, blinks instead.

Below is what #define does, why LED_BUILTIN is one, and the five ways a #define goes wrong where a const would not, each built in Mokxi with what it printed or the error it gave.

Want the step-by-step version? The lesson "A program is a list" walks through this with checkpoints.
Open the lesson

## A name for a pin

Here is the whole sketch running above. LAMP is used three times and set once. Without the name, changing the pin would mean finding every 13 in the sketch and hoping none of them meant something else.

const means the value is fixed. Try to change it, LAMP = 12; inside setup(), and the build stops: clang says cannot assign to variable 'LAMP' with const-qualified type 'const int', and the Arduino IDE’s GCC says assignment of read-only variable 'LAMP'. That is the point: a pin number that changes while the sketch runs is a bug.

firmware/uno/examples/cpphello (the sketch running above)

## What #define really does

A #define is not a variable. It is find and replace, done to the text of the sketch before the compiler reads it. #define LAMP 13 has no type and takes no memory; every LAMP after it simply becomes 13.

You use them already. LED_BUILTIN is #define LED_BUILTIN 13 in the Uno’s core, and printing it printed 13. HIGH is a #define for 1 and printed 1. They are written in capitals by custom, so a name in capitals tells the reader it might be a #define, and a const is usually written in capitals too, because it does the same job.

## The semicolon and the equals sign

A #define line is not a statement, so it takes no semicolon and no equals sign. With #define LED 13;, the semicolon is pasted in along with the 13, so pinMode(LED, OUTPUT); becomes pinMode(13;, OUTPUT);. Clang says expected ')', with a note pointing back at the #define, expanded from macro 'LED'; GCC says expected ')' before ';' token. The error is on the line that uses the name, not the line that is wrong, which is why it takes so long to find.

#define LED = 13 fails the same way, as pinMode(= 13, OUTPUT), and clang says expected expression. A const cannot make either mistake: const int LED = 13; is an ordinary statement, with its equals sign and its semicolon where they belong.

A semicolon pasted in

## Missing parentheses

Because a #define pastes text, the sum it pastes mixes with whatever is around it. With #define WIDTH 10 + 5, WIDTH * 2 becomes 10 + 5 * 2 and printed 20, where const int WIDTH_C = 10 + 5; doubled printed 30. A #define that takes a value is worse: #define SQUARE(x) x * x turned SQUARE(1 + 2) into 1 + 2 * 1 + 2 and printed 5. With parentheses around every use and around the whole, ((x) * (x)), it printed 9.

A #define also takes no type, so its sum is done in int. #define SECONDS 60 * 60 * 24 printed 20864 for a day, with an overflow warning, where const long SECONDS_C = 60L * 60 * 24; printed 86400. The data types page explains why.

Pasted sums

## Names that collide

A #define replaces its name everywhere after it, in every function, with no exceptions. After #define LED 13, a line inside setup() that says int LED = 5; becomes int 13 = 5;, and clang says expected unqualified-id. The same thing happens with the names the Arduino core has already defined. const float PI = 3.14; looks harmless and stopped the build with the same error, because PI is already a #define in the core and the line became const float 3.14159... = 3.14;.

Define the same name twice and the second one wins, with only a warning. #define LED 13 followed by #define LED 12 printed 12, and the build tab said 'LED' macro redefined. Two consts with the same name in the same place stop the build, which is the safer answer.

## What #define is still for

Use const for numbers, pins and settings, and constexpr for a value worked out from others, as in constexpr int LIMIT = COUNT * 2;, which printed 6. A const int can size an array, too: int pins[COUNT] with COUNT at 3 measured 6 bytes, three 2-byte ints.

A #define is the right tool for switching code on and off before it is compiled. With #define DEBUG at the top, the lines between #ifdef DEBUG and #endif are built in, and our sketch printed "start" and "debug: setup done". Delete the #define and the same sketch printed only "start", and the debug lines were never compiled at all.

Debug lines that come and go

## Questions

Should I use const or #define in Arduino?

Use const for pin numbers and settings. It has a type, follows the normal rules for names, and cannot paste in a stray semicolon or sum. Keep #define for switching code on and off with #ifdef.

Does a #define use memory on an Arduino?

No. It is replaced before compiling, so only the number is left in the code.

Why does #define with a semicolon give an error?

Because the semicolon is pasted in with the value. #define LED 13; turns pinMode(LED, OUTPUT) into pinMode(13;, OUTPUT), and the error appears on that line, not on the #define.

What does "expected unqualified-id" mean with a #define?

A name you used is already a #define, so it was replaced by a number where the compiler wanted a name. Arduino defines PI, HIGH, LOW, INPUT and others; pick a different name.

What is the difference between const and constexpr?

Both make a value that cannot change. constexpr also promises the compiler can work it out while building, so it can be used anywhere a fixed number is needed, such as an array size.

What is the difference between const int and int?

An int can change while the sketch runs and a const int cannot. Write `LAMP = 12;` after `const int LAMP = 13;` and the build stops with cannot assign to variable 'LAMP' with const-qualified type 'const int'; the Arduino IDE’s GCC says assignment of read-only variable 'LAMP'. That error is the point: a pin number cannot be changed by accident.

Related

## Keep going

Arduino Data Types: int, long, float and byte Arduino "expected ';' before" and Similar Errors Arduino Compile Errors Explained, With the Fixes Arduino "Was Not Declared in This Scope": Every Fix Arduino Functions: Write It Once, Call It Anywhere Arduino "expected unqualified-id": Causes and Fixes The online Arduino compiler The free Arduino simulator

Sources

## Where the facts on this page come from

- Arduino reference: #define
- Arduino reference: const

## Build this for real

Open the editor, change a value and watch the number move with it. Nothing to install, and no account needed.

Start building free Open the editor
