آردوینومقدماتی۱۱ دقیقه مطالعهArduino IDE 2.x / Uno R3

خطاهای کامپایل و معنی پیام‌های کامپایلر

خطاهای رایج کامپایل آردوینو را با متن دقیق پیام، علت و راه‌حل می‌شناسید؛ از جاافتادن سمی‌کالن تا حروف فارسی داخل کد و ناهم‌خوانی نوع داده.

آنچه در این درس می‌آموزید

  • بفهمید کامپایلر چه می‌کند و پیام خطا را با قالب file:line:col بخوانید
  • شش خطای پرتکرار کامپایل را با متن دقیقشان تشخیص دهید و رفع کنید
  • تفاوت هشدار (Warning) و خطا (Error) و خطر «کامپایل با هشدار» را بدانید
نویسنده: تیم داکنامه · بازبینی: ۲۰۲۶-۱۰-۳۱
فهرست مطالب

دکمهٔ Verify را زده‌اید و کنسول پر از متن قرمز شده است. خبر خوب: خطای کامپایل بی‌خطرترین خطاست؛ برد شما هیچ‌آسیبی نمی‌بیند و کامپایلر تقریباً همیشه آدرس دقیق مشکل را به شما می‌دهد. در این درس یاد می‌گیرید زبان کامپایلر را بخوانید و شش خطای پرتکرار را با یک نگاه تشخیص دهید.

کامپایل یعنی چه؟

میکروکنترلر ATmega328P روی برد Uno فقط زبان صفر و یک می‌فهمد. کامپایلر (Compiler) — در آردوینو از زنجیرهٔ ابزار avr-gcc استفاده می‌شود — کد C++ شما را به کد ماشین ترجمه می‌کند. کامپایلر بسیار سخت‌گیر است: قبل از ترجمه، قواعد دستوری را سطربه‌سطر چک می‌کند و با نخستین خطا متوقف می‌شود. به همین دلیل خطای کامپایل تقریباً همیشه یعنی «یک غلط نوشتاری در کد»، نه مشکلی در برد.

محل خطاها در IDE 2 کنسول پایین پنجره است. قالب هر پیام چنین است:

text
blink.ino:7:3: error: expected ';' before '}' token

یعنی فایل blink.ino، خط ۷، ستون ۳. همیشه از همین قالب استفاده کنید تا شمارهٔ خط را پیدا کنید؛ شمارهٔ خط روی نوار کنار ویرایشگر مشخص می‌شود. طبق درس عیب‌یابی، کنسول را از پایین به بالا بخوانید و نخستین خطا را بگیرید.

expected ';' و expected '}'

رایج‌ترین خطای دنیای C++. کامپایلر انتظار سمی‌کالن دارد اما به } می‌رسد:

cpp
// Wrong
int ledPin = 13
cpp
// Right
int ledPin = 13;

اگر خودِ سمی‌کالن نبود و یک { بسته نشده مانده باشد، در پایان فایل این را می‌بینید:

text
expected '}' at end of input

این یعنی یک { جایی باز شده و تا آخر فایل بسته نشده است؛ از آخرین { شمرده‌نشده شروع کنید و جفت‌ها را بشمارید.

'xyz' was not declared in this scope

یعنی «این نام را اصلاً نمی‌شناسم». سه علت دارد:

cpp
// Wrong
void loop() {
  digitalWrite(ledpin, HIGH);  // declared as ledPin
}
cpp
// Right
void loop() {
  digitalWrite(ledPin, HIGH);
}
  1. غلط تایپی — ledpin به‌جای ledPin.
  2. حساسیت به بزرگی و کوچکی حروف — C++ بین ledPin و ledpin فرق می‌گذارد؛ pinMode را هم pinmode ننویسید.
  3. تعریف نشدن متغیر — نامی را استفاده کرده‌اید که هیچ‌جا تعریف یا اعلام نشده است.

حروف فارسی داخل کد: stray و expected unqualified-id

کد فقط انگلیسی می‌شود؛ یک حرف فارسی داخل کد (مثلاً هنگام تایپ کامنت فارسی در جای اشتباه، یا گیومهٔ «فارسی» به‌جای گیومهٔ کد) بایت‌هایی تولید می‌کند که کامپایلر نمی‌شناسد:

text
stray '\331' in program

عدد داخل پیام همان بایت ناشناخته است و بسته به حرف تایپ‌شده فرق می‌کند؛ گیومهٔ خمیدهٔ انگلیسی هم معمولاً stray '\342' in program می‌دهد. اگر خط ادامه پیدا کند، کامپایلر ممکن است بلافاصله این را هم اضافه کند:

text
expected unqualified-id before 'int'

این یعنی «توانستم تا اینجا بخوانم، اما بعدش چیزی نیست که انتظار تعریفی داشت». هر دو خطا معمولاً در یک خط هستند؛ خطِ اعلام‌شده در پیام را باز کنید و کاراکتر غیرانگلیسی را پاک کنید.

invalid conversion و cannot convert

کامپایلر چک می‌کند نوع دادهٔ هر ورودی تابع با آنچه تعریف شده یکی باشد:

cpp
// Wrong
digitalWrite(13, "HIGH");  // "HIGH" is text, not HIGH
cpp
// Right
digitalWrite(13, HIGH);

پیام دقیقش چنین است:

text
invalid conversion from 'const char*' to 'int'

یعنی رشتهٔ متنی (const char*) را جای عدد (int) گذاشته‌اید. در مقداردهی اولیه همیشه این شکل را می‌بینید:

text
cannot convert 'const char*' to 'int' in initialization

مثلاً int x = "5"; — عدد ۵ را بدون گیومه بنویسید.

too few و too many arguments

تعداد ورودی‌های تابع باید دقیقاً درست باشد:

text
too few arguments to function 'void digitalWrite(int, int)'

یعنی ورودی کم داده‌اید، مثل digitalWrite(13); که حالت HIGH یا LOW ندارد. حالت برعکس:

text
too many arguments to function 'void delay(long unsigned int)'

مثل delay(1000, 500); که یک ورودی اضافه دارد. شمارهٔ خط را ببینید و پرانتز را با امضای تابع در مرجع رسمی مقایسه کنید.

کد بیرون از تابع: 'Serial' does not name a type

هر دستور اجرایی باید داخل setup() یا loop() باشد. اگر خطی را بالای توابع بنویسید، کامپایلر آن را به‌عنوان «تعریف» می‌خواند و نمی‌تواند؛ بسته به خط، پیام‌هایی مثل این می‌بینید:

text
'Serial' does not name a type

یا

text
expected constructor, destructor, or type conversion before '.' token

راه‌حل: خط را ببرید داخل setup() (اگر باید یک بار اجرا شود، مثل Serial.begin(9600)) یا داخل loop().

هشدار، نه خطا

کنسول دو نوع پیام می‌دهد: خطا (Error) کامپایل را متوقف می‌کند و پیام exit status 1 می‌آید؛ هشدار (Warning) یعنی «کد ترجمه شد، اما چیزی مشکوک است» — مثل متغیری که تعریف کرده‌اید اما استفاده نکرده‌اید. کد با هشدار کامپایل می‌شود و آپلود هم می‌شود، اما رفتار غلط احتمالی در کمین است: مثلاً مقایسهٔ عدد علامت‌دار و بی‌علامت، یا قطع کردن قسمتی از مقدار در تبدیل نوع، نتیجهٔ نادرست اما بی‌صدا می‌دهد. قانون: هشدارها را هم صفر کنید، نه فقط خطاها را.

جدول مرجع سریع

پیام خطا (دقیق) رایج‌ترین علت راه‌حل
expected ';' before ... نبود سمی‌کالن در خط قبل سمی‌کالن انتهای خط قبل را اضافه کنید
expected '}' at end of input آکولاد بازِ بسته‌نشده جفت‌های { و } را بشمارید
'xyz' was not declared in this scope غلط تایپی، بزرگی/کوچکی، یا تعریف‌نشدن نام را با محل تعریف مقایسه کنید
stray '\331' in program حرف فارسی یا گیومهٔ خمیده داخل کد کاراکتر غیرانگلیسی را پاک کنید
expected unqualified-id before ... ادامهٔ خطای کاراکتر ناشناخته خط اعلام‌شده را اصلاح کنید
invalid conversion from 'const char*' to 'int' رشته به‌جای ثابت عددی "HIGH" را به HIGH تغییر دهید
cannot convert 'const char*' to 'int' in initialization مقدار رشته‌ای برای متغیر عددی عدد را بدون گیومه بنویسید
too few arguments to function ... ورودی کمتر از تعریف تابع امضای تابع را در مرجع ببینید
too many arguments to function ... ورودی اضافه ورودی اضافه را حذف کنید
'Serial' does not name a type دستور اجرایی بیرون از تابع خط را داخل setup یا loop ببرید

تمرین‌ها

تمرین

تمرین ۱ — سه خطا در یک اسکچ

در کد زیر دقیقاً سه خطای کامپایل عمدی گذاشته‌ایم. هر سه را پیدا کنید، پیام احتمالی هر کدام را حدس بزنید و سپس نسخهٔ اصلاح‌شده را بنویسید:

cpp
int ledPin = 13

void setup() {
  pinMode(ledpin, OUTPUT);
}

void loop() {
  digitalWrite(ledPin, HIGH)
  delay(1000);
  digitalWrite(ledPin, LOW);
  delay(1000);
}
نمایش راه‌حل

خطاها: (۱) سمی‌کالن جاافتاده در انتهای int ledPin = 13 که پیام expected ';' before 'void' می‌دهد؛ (۲) ناهم‌خوانی حروف در ledpin به‌جای ledPin که پیام 'ledpin' was not declared in this scope می‌دهد؛ (۳) سمی‌کالن جاافتاده در انتهای digitalWrite(ledPin, HIGH) که پیام expected ';' before 'delay' می‌دهد. نسخهٔ اصلاح‌شده:

cpp
int ledPin = 13;

void setup() {
  pinMode(ledPin, OUTPUT);
}

void loop() {
  digitalWrite(ledPin, HIGH);
  delay(1000);
  digitalWrite(ledPin, LOW);
  delay(1000);
}

این اسکچ بدون هیچ خطا و هشداری کامپایل می‌شود.

:::

خلاصه

  • کامپایل با avr-gcc کد شما را به کد ماشین ترجمه می‌کند و با نخستین خطا می‌ایستد.
  • قالب پیام خطا file:line
    است؛ شمارهٔ خط را از همان‌جا بگیرید.
  • رایج‌ترین خطاها سمی‌کالن و آکولاد جاافتاده و غلط تایپی نام‌ها هستند.
  • حروف فارسی داخل کد خطای stray '\...' می‌دهند؛ کد همیشه انگلیسی است.
  • هشدار یعنی کد کامپایل شده اما مشکوک است؛ هشدارها را هم صفر کنید.

کدتان حالا سبز کامپایل می‌شود؛ در درس بعدی می‌رویم سراغ مرحلهٔ بعدی زنجیره، یعنی جایی که Verify سبز است اما آپلود روی برد شکست می‌خورد.

منابع و ارجاع‌ها

درس‌های مرتبط