در قسمت قبل آموزش برنامه نویسی C به بررسی بیت ها در امبدد C پرداختیم. در این قسمت به دستورات کنترلی زبان C برای امبدد سیستم ها می پردازیم.
کامپیوتر یک ابزار قدرتمند است زیرا میتواند بر اساس دادههایی که دریافت میکند تصمیم بگیرد. برای مثال، یک کامپیوتر میتواند در صورت فشاردادن دکمهای، یک LED را روشن کند و در صورت فشارندادن آن، LED را خاموش کند. در ادامه این فصل، با استفاده از دستورات شرطی و کنترلی C، برنامهای برای دستگاه خود (مثلاً یک میکروکنترلر) خواهیم نوشت که به فشاردادن دکمهها پاسخ میدهد.
دستور شرطی if
ما از دستور if برای اجرای برخی کدها فقط درصورتیکه یک شرط خاص درست باشد استفاده میکنیم. در اینجا شکل کلی این دستور آمده است:
1 2 | if (condition) statement; |
برای اجرای شرطی بیش از یک دستور، مجموعه دستوراتی که تحتتأثیر شرط قرار میگیرند را داخل آکولاد ({}) قرار دهید، همانطور که در ادامه نشاندادهشده است. C مجموعه دستورات را بهعنوان یک بلوک واحد در نظر میگیرد:
1 2 3 4 5 6 | if (condition) { statement; statement; statement; // ... } |
C هر چیزی غیر از صفر را بهعنوان درست و صفر را بهعنوان غلط در نظر میگیرد؛ بنابراین، اگر شرط غیرصفر باشد، دستورات اجرا میشوند. اگر شرط صفر باشد، اجرا نمیشوند.
عملگر های مقایسه را میتوانید در جدول زیر مشاهده کنید.
عملگر | توضیحات |
== | مساوی |
< | کمتر از |
<= | کمتر یا مساوی |
!= | نامساوی |
> | بزرگتر از |
>= | بزرگتر یا مساوی |
جدول 5-1: عملگرهای مقایسه
بهعنوانمثال، اگر میخواهید کد فقط در صورتی اجرا شود که یک متغیر مقدار ۵ داشته باشد، میتوانید از عملگر مساوی (==) بهصورت زیر استفاده کنید:
1 2 3 | if (aNumber == 5) { printf("The number is 5\n"); } |
✅نکته
زبان C اجازه انتساب درون شرط را میدهد. برای مثال، کد زیر که یک مقدار ۷ را به یک متغیر در داخل دستور if اختصاص میدهد، مجاز است:
1 2 3 | if (aNumber = 7) { printf("Something happened\n"); } |
اما این کد معادل کد زیر است که بعد از انتساب بررسی میکند آیا متغیر برابر با صفر است:
1 2 3 4 | aNumber = 7; // Assignment if (aNumber != 0) { // Test against zero printf("Something happened\n"); } |
این با شرط زیر که بررسی میکند آیا متغیر برابر با ۷ است یکسان نیست:
1 | if (aNumber == 7) |
این مشکل در روزهای اولیه زبان C ، زمانی که فناوری کامپایلر بهاندازه امروز پیشرفته نبود، مشکل بزرگی محسوب میشد. ممکن بود بهاشتباه کدی مانند کد زیر بنویسید که بسیار پیچیدهتر است:
1 2 3 4 | aNumber = 5; if (aNumber = 7) { // Notice the missing '=' character. printf("Something happened\n"); } |
کد داخل دستور if اجرا میشد، زیرا به متغیر دوباره مقدار ۷ اختصاص داده میشد که بهعنوان یک مقدار غیرصفر، بلافاصله شرط را درست میکرد، حتی اگر شما قصد داشتید مقدار aNumber برابر با ۵ باشد، نه ۷. با کامپایلر مدرن GCC، انتساب در یک شرط یک اخطار تولید میکند:
1 2 3 | equal.c:14:5: warning: suggest parentheses around assignment used as truth value [-Wparentheses] if (aNumber = 7) { |
در اینجا، GCC به شما میگوید که اگر میخواهید اخطار را بیاثر کنید و واقعاً میخواهید یک دستور انتساب و یک دستور if را ترکیب کنید، باید کد را بهصورت زیر بنویسید:
1 | if ((aNumber = 7)) { // Very very lousy programming |
من این نظر را اضافه کردم؛ زیرا به نظرم ترکیب دستورات روش برنامهنویسی ضعیفی است. هر دستور باید یک کار انجام دهد. بهعنوانمثال، وقتی لازم است یک انتساب و یک بررسی انجام دهید، ابتدا انتساب را انجام دهید و سپس بررسی را انجام دهید.
دستور شرطی if/else
از دستور شرطی if/else زمانی استفاده میکنیم که بخواهیم مجموعهای از دستورات را درصورتیکه شرط درست باشد اجرا کنیم و مجموعهای دیگر از دستورات را درصورتیکه شرط نادرست باشد، اجرا کنیم.
برای مثال، کد زیر را در نظر بگیرید:
1 2 3 4 5 | if ((number % 2) == 0) { printf("Number is even\n); } else { printf("Number is odd\n); } |
اگر مقدار متغیر number هنگام تقسیم بر ۲ باقیماندهای برابر با ۰ داشته باشد، این کد پیامی چاپ میکند که نشان میدهد عدد زوج است؛ در غیر این صورت، پیامی چاپ میکند که نشان میدهد عدد فرد است.
اکنون به یکی دیگر از پیچیدگیهای زبان C میرسیم: لازم نیست پس از if یا else آکولاد ({}) را دور یک دستور واحد قرار دهید. کد زیر را در نظر بگیرید که بهعمد تورفتگی اشتباهی دارد:
1 2 3 4 5 | if (a == 1) if (b == 2) printf("Condition orange\n"); else printf("Condition pink\n"); |
دستور else به کدام if تعلق دارد، if اول یا if دوم؟
گزینههای پاسخ:
- if: if (a == 1)
- if: if (b == 2)
- اگر کد خود را به این شکل ننویسید، نیازی به نگرانی در مورد چنین سؤالات ساده ای نیست.
بیایید از گزینه c استفاده کنیم و کد را بازنویسی کنیم. در کد زیر دستور else به کدام if تعلق دارد؟
1 2 3 4 5 6 7 | if (a == 1) { if (b == 2) { printf("Condition orange\n"); } else { printf("Condition pink\n"); } } |
در اینجا، میتوانید تشخیص دهید که else به if دوم تعلق دارد. این پاسخ رسمی به سؤال قبلی نیز هست، اما با نوشتن واضح کد خود، میتوانید بدون نیاز به بررسی دقیق استاندارد زبان C، به پاسخ برسید.
لازم به ذکر است که برخی از راهنماهای سبک کدنویسی الزام میکنند که همیشه بدنه if را داخل آکولاد قرار دهید؛ بااینحال، این تصمیمی است که بهتر است به برنامهنویس واگذار شود.
دستورات حلقه (Loop)
حلقه یک ویژگی برنامهنویسی است که تا زمانی که شرطی برقرار باشد، کد خاصی را تکرار میکند. C دارای سه دستور حلقه است: while, for و do/while. ما با while شروع میکنیم، زیرا سادهترین است، و سپس for. ما وارد do/while نمیشویم؛ زیرا بهندرت استفاده میشود.
حلقه while
فرم کلی دستور while به شرح زیر است:
while (شرط)
دستور;
بهخاطر داشته باشید که دستور میتواند یک دستور C واحد یا مجموعهای از دستورات محصور در {} باشد. برای اینکه ببینیم یک حلقه while چگونه میتواند مفید باشد، بیایید برنامهای بنویسیم که اعداد ۱ تا ۱۰ را آزمایش کند تا ببیند کدام یک زوج و کدام فرد هستند، همانطور که در کد ۵-۱ نشاندادهشده است.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /* * Test to see if the numbers 1 through 10 are even * or odd. * #include <stdio.h> int main() { int aNumber; // Number to test for oddness aNumber = 1; while (aNumber <= 10) { if ((aNumber % 2) == 1) { printf("%d is odd\n", aNumber); } else { printf("%d is even\n", aNumber); } ++aNumber; } return (0); } |
کد ۵-۱: بررسی زوج یا فرد بودن
در تابع main، متغیری به نام aNumber تعریف میکنیم تا مقداری را که در حلقه while خودآزمایش میکنیم، نگه دارد. سپس آن متغیر را روی ۱ تنظیم میکنیم.
سپس، حلقه while را تنظیم میکنیم تا زمانی که aNumber کمتر یا مساوی ۱۰ باشد، اجرا شود. داخل حلقه (یعنی داخل براکتها) از دستور شرطی if/else که در بخش قبلی این فصل معرفی شد برای بررسی باقیمانده تقسیم aNumber بر ۲ استفاده میکنیم. این به ما میگوید که عدد زوج است یا فرد.
قبل از اینکه حلقه را تمام کنیم، با ++aNumber، ۱ به aNumber اضافه میکنیم؛ بنابراین، دفعه بعد که حلقه اجرا شود، aNumber مقدار ۲ خواهد داشت و به همین ترتیب ادامه پیدا میکند. در نهایت، هنگامی که مقدار aNumber به ۱۱ میرسد، حلقه پایان مییابد و برنامه با مقدار برگشتی ۰ خارج میشود.
وقتی این برنامه اجرا میشود، خروجی به این صورت است:
1 2 3 4 5 6 7 8 9 10 | 1 is odd 2 is even 3 is odd 4 is even 5 is odd 6 is even 7 is odd 8 is even 9 is odd 10 is even |
حلقه for
حلقه while ما سه جزء اصلی داشت: یک دستور مقداردهی اولیه (aNumber = 1)، یک دستور بررسی (بررسی اینکه آیا aNumber بزرگتر یا مساوی 10 است) و یک دستور برای افزایش مقدار متغیر پس از اجرای حلقه (++aNumber).
این الگوی طراحی (مقداردهی اولیه، شرط و افزایش) آنقدر رایج است که دستور خاص خود را دارد: دستور for. ما این دستور را بهصورت زیر مینویسیم:
1 | for (initialization; condition; increment) |
برای دیدن نحوه عملکرد آن، بیایید حلقه while خود را به یک حلقه for تبدیل کنیم. کد زیر همان برنامه زوج یا فرد را با استفاده از دستور for نشان میدهد:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | /* * Test to see if the numbers 1 through 10 are even * or odd. */ #include <stdio.h> int main() { int aNumber; // Number to test for oddness for (aNumber = 1; aNumber <= 10; ++aNumber) { if ((aNumber % 2) == 1) { printf("%d is odd\n", aNumber); } else { printf("%d is even\n", aNumber); } } return (0); } |
توجه داشته باشید که شرط for شامل سه دستور است که با سمیکالن از هم جدا شدهاند.
هر کدام از این دستورات ممکن است در حلقه for وجود نداشته باشند. برای مثال، میتوانستیم برنامه خود را با مقداردهی اولیه aNumber قبل از ورود به حلقه بنویسیم:
1 2 | aNumber = 1; for (; aNumber <= 10; ++aNumber) { |
از طرف دیگر، میتوانیم مقدار متغیر را در بدنه حلقه بهجای شرط for افزایش دهیم:
1 2 3 | for (aNumber = 1; aNumber <= 10;) { // Oddness test ++aNumber; |
بااینحال، اگر شرط حذف شود، حلقه هرگز پایان نخواهد یافت. به همین دلیل است که دستور زیر برای همیشه ادامه دارد:
1 | for (;;) |
ما از این حلقه در برنامههای امبدد خود استفاده میکنیم، زیرا هرگز نباید متوقف شوند.