در قسمت قبل برنامه ساده Hello World را اجرا کردیم. در این قسمت میخواهیم درک عمیق تر از آن و اجزای درونی آن پیداکنیم.
بررسی المان های ابتدایی کدنویسی در برنامه قسمت قبل
حالا بیایید خطبهخط برنامهای که در قسمت قبل اجرا کردیم، را بررسی کنیم تا ببینیم هر بخش چه کاری انجام میدهد. به خط اول توجه کنید:
1 | #include <stdio.h> |
ما برای ساختن برنامهی خود، از اجزايی استفاده میکنیم که کامپایلر در اختیار ما قرار میدهیم – بهعنوانمثال، پکیج ورودی/خروجی (I/O) استاندارد کتابخانه استانداردی است که با نصب GCC در اختیار ما قرار گرفته است، توابع موجود در این پکیج در فایل /usr/include/stdio. تعریف شدهاند. (مسیر قرار گیری آن در ویندوز ممکن است کمی متفاوت باشد.)
شاید با خود فکر کنیم در برنامه ساده ما چه نیازی به استفاده از این پکیج استاندارد بودهاست، پاسخ ساده است تابع print بخشی از کتابخانه استاندارد stdio است و با اضافه کردن ان به نحوی که در خط اول برنامه ما قرار گرفته امکان دسترسی به توابع آن برای ما فراهم شده است.(یک تست ساده: خط اول کد را حذف کنید و دوباره برنامه را اجرا کنید به خطاها و توابعی که دچار خطا شدهاند دقت کنید. این کنجکاویهای ساده راه یادگیری عمیقتر را برای ما هموارتر میکنند.)
خط بعدی، نقطه شروع برنامه را تعریف میکند:
1 | int main() |
main نشاندهنده بدنهی اصلی برنامه است به عبارت دیگر main نقطه ورودی اصلی برنامه است. تمام برنامهها از main شروع میشوند و از آنجا تمام کدهای دیگر فراخوانی میشوند.
پس از main، مجموعهای از دستورات داخل کروشه آورده شدهاند( این دستورات بدنه تابع main ما را تشکیل میدهند):
1 2 3 | { ... } |
کروشهها
کاربرد اصلی کروشه ها گروهبندی دستورات می باشد.
شاید تلاش کرده باشید که تعداد فضاهای خالی درون کروشه را مطابق مثالی که ما آوردهایم قرار دهید، اما باید بگویم اصلا نگران نباشید، کامپایلر C حساس به تعداد فاصلهها نیست. ما میتوانستیم از هیچ فاصلهای استفاده نکنیم، اما عدم استفاده از فضای خالی، ما را در درک برنامه دچار مشکل میکند، بنابراین بیشتر برنامهنویسان C کدهای خود را فاصلهگذاری میکنند فاصله گذاری های با قاعده به خوانایی برنامه ما کمک میکند.
در داخل کروشه، اولین دستور قابلاجرا واقع شده است:
1 | printf("Hello World!\n"); |
این دستور به برنامه میگوید که از تابع ورودی/خروجی استاندارد printf برای نمایش یک رشته در محل خروجی استاندارد (ترمینال ما) استفاده کند. \n کاراکتر ویژهای در این رشته است. کاراکتر بکاسلش (\)، کاراکتر فرار (escape) نامیده میشود. بک اسلش(escape) به C میگوید که کاراکتر پس از آن باید بهعنوان کد در نظر گرفته شود نه کاراکتر n .
n به C میگوید که یک خط جدید در خروجی قرار دهد، پس در این صورت کاراکتر بعدی روی خط جدید چاپ خواهد شد. برخی از کاراکترهای فرار پرکاربرد در جدول ۱-۱ نشاندادهشده است.
کاراکتر | نتیجه |
\n | خط جدید |
\t | tab |
\” | “ |
\\ | \ |
\r | Carriage بازگشت |
جدول ۱-۱: کاراکترهای فرار (escape) پرکاربرد
سرانجام، برنامه با این دستور به پایان میرسد:
1 | return (0); |
زمانی که خط اجرای برنامه ما به return برسد از برنامه خارج میشود، همچنین خروجی برابر با 0 به سیستم عامل بازگردانده میشود که نشان دهندهی این است که برنامه به شکل نرمال خاتمه یافته است. کد خروجی غیر صفر نشاندهنده وجود خطا است.( اگر ما return را اولین خط بعد از کروشه قرار دهیم در ترمینال دیگر چیزی برای ما نمایش داده نمیشود چرا که برنامه قبل از رسیدن به printf پایان یافته است)
افزودن Comment
تا اینجا به نوشتن کد محدود بودیم. بهعبارتدیگر، تمام چیزهایی که دیدیم، برای خوانده و پردازششدن توسط کامپیوتر بود. جدا از کد، برنامهها میتوانند شامل توضیحاتی باشند که توسط کامپایلر دیده نمیشود؛ بلکه این توضیحات برای افرادی که برنامه را مشاهده میکنند است. توضیحات معمولاً با /* شروع میشوند و با */ خاتمه مییابند. بهعنوانمثال:
1 | /* Hello World – A nothing program */ |
توضیحات به ما میگوید، برنامهنویسی که این برنامه را نوشته دربارهی برنامه چه طرز فکری داشته است. بیایید چند توضیح به ابتدای برنامهای که نوشتهایم اضافه کنیم:
1 2 3 4 5 6 7 8 9 | /* * Hello World -- not the most complicated program in the universe but useful as a starting point. * Usage: * 1. Run the program. * 2. See the world. * / |
*/ نوع دیگری از توضیحات با // آغاز میشوند و تا انتهای خط ادامه مییابد. بعد از اینکه برنامههای بیشتری دیدید و نوشتید، میتوانید تصمیم بگیرید از کدام روش استفاده کنید.
همیشه هنگام نوشتن برنامهی خود، توضیحات را به کد خود اضافه کنید، زیرا زمانی که دارید کد مینویسید، دقیقاً میدانید چه کاری انجام میدهید درصورتیکه پنج دقیقه بعد ممکن است فراموش کنید؛ اما پنجروز بعد، حتماً فراموش خواهید کرد.
پیشنهاد من این است که هنگام یادگیری کد نویسی C، عادت به نوشتن توضیحات در کد خود کنید. برنامهنویسان خوب به نوشتن توضیحات کامل و دقیق در برنامه خود علاقمندند!
بهبود برنامه و اتوماسیون فرایند ساخت
برنامه کوچکی که نوشتیم را در نظر بگیرید (Hello World)، کامپایل دستی این برنامه مشکلی ایجاد نمیکند. اما وقتی به برنامهای با هزاران ماژول میرسیم، این که کدام بخشها باید کامپایل شوند و کدام بخشها نیاز به کامپایل ندارند، کار دشواری است و احتمال خطا زیاد است. لازم است فرایند را بهگونهای اتوماتیک کنیم تا کارآمد باشد و از خطاهای انسانی جلوگیری کنیم.
در این بخش، برنامه خود را بهبود میبخشیم و فرایند ساخت را بهصورت اتوماتیک انجام میدهیم. بهتر است با یک دستور و بدون نیاز به پارامتر، برنامه بتواند ساخته شود تا نشان دهد فرایند ساخت ما پایدار و دقیق است.
برنامه make
یکی از مشکلات برنامه نویسی با C، این است که هر بار میخواهیم برنامه را اجرا، باید کامند کامپایل را وارد کنیم. این کار برای یک برنامه با چند هزار فایل در آن که هرکدام باید کامپایل شوند، خستهکننده و زمانبر است. برای اتوماتیک کردن فرایند ساخت، از برنامه make استفاده خواهیم کرد. این برنامه بهعنوان ورودی، یک فایل به نام makefile میگیرد که به make میگوید چگونه باید یک برنامه را بسازد.
یک فایل به نام Makefile بسازید که حاوی موارد زیر باشد (در macOS یا Linux):
1 2 3 4 | CFLAGS=-ggdb -Wall -Wextra all: hello hello: hello.c gcc $ (CFLAGS) -o hello hello.c |
در ویندوز، makefile باید شامل موارد زیر باشد:
1 2 3 4 | CFLAGS=-ggdb -Wall -Wextra all: hello.exe hello.exe: hello.c gcc $(CFLAGS) -o hello.exe hello.c |
دقت کنید که خطوط دارای تورفتگی(indented lines) لازم است با یک Tab شروع شوند و اگر به جای آن هشت فضای خالی قراردهید کار نخواهد کرد. (طراحی فایل بسیار بد است، اما مجبوریم با آن کار کنیم!)
خط اول، یک ماکرو (macro) (که در این برنامه cflags است) تعریف میشود. با این تعریف، هرگاه (CFLAGS)$ را در فایل make استفاده کنیم، برنامه make این را با ggdb -Wall -Wextra– جایگزین خواهد کرد. سپس، تارگت all را تعریف میکنیم که به طور قراردادی تارگت پیشفرض است.
هنگامی که make بدون پارامتر اجرا میشود،اولین فانکشن اجرا می شود،در اینجا یعنی all: hello، به برنامه make میگوید: “برای ساختن all ، به ساختن hello نیاز دارید”. دو خط آخر فایل make، مشخصات hello (یا hello.exe در ویندوز) هستند. اینها به make میگویند که hello از hello.c ساخته میشود. با اجرای دستور gcc $(CFLAGS) -o hello hello.c باتوجهبه اینکه این دستور شامل ماکروی تعریف شده است، $ (CFLAGS) به ggdb -Wall -Wextra- تبدیل میشود. اگر دقت کنید با این ماکرو ما چند flag اضافه به کامپایل افزودهایم. در بخش بعدی به بررسی آنها خواهیم پرداخت.
حال بیایید با استفاده از دستور make، برنامه را بسازیم:
1 2 3 | $ make gcc -ggdb -Wall -Wextra -o hello hello.c |
همانطور که مشاهده میکنید، برنامه دستورات لازم برای ساختن فایل را اجرا کرد؛ یعنی برنامه make هوشمند است، برنامه میداند که hello از hello.c ساخته میشود، بنابراین تاریخهای اصلاح این دو فایل را بررسی میکند. اگر hello جدیدتر باشد، نیازی به کامپایل مجدد نیست، بنابراین اگر شما دوباره تلاش کنید تا برنامه را بسازید، پیام زیر را دریافت خواهید کرد:
1 | make: Nothing to be done for 'all'. |
این همیشه رفتار صحیح نیست. اگر ما فلگ ها را در فایل make تغییر دهیم، فرایند کامپایل را تغییر دادهایم و باید برنامه خود را دوباره بسازیم. بااینحال، make از این تغییر آگاه نیست و مگر اینکه ما hello.c را ویرایش کرده و فایل را ذخیره کنیم یا فایل خروجی را حذف کنیم.
فلگ های کامپایلر
کامپایلر GCC امکانات زیادی دارد. در واقع فهرست امکانات این کامپایلر بیش از هشت صفحه است ولی نیازی نیست که در مورد شناختن همه آنها نگران باشیم . بیایید به بررسی گزینههایی که برای برنامه خود استفاده کردهایم، بپردازیم:
ggdb
برنامه را بهگونهای کامپایل میکند که ما بتوانیم آن را دیباگ کنیم. در بیشتر موارد، اطلاعات دیباگ را به فایل خروجی اضافه میکند که به دیباگر اجازه میدهد بفهمد چه اتفاقی میافتد.
Wall
مجموعهای از هشدارها را فعال میکند که کد صحیح و مشکوک را مشخص میکند. (این دوره به شما آموزش میدهد که کد مشکوک ننویسید).
Wextra
با فعال کردن هشدارهای اضافی، کد ما دقیقتر میشود.
o hello
خروجی برنامه ما را در فایل hello قرار میدهد. (این گزینه برای کاربران ویندوز -o hello.exe است.)
در قسمت دوم آموزش امبدد C با هم با کد نویسی مبتدی C، نحوه افزودن کامنت، اتوماسیون فرایند ساخت و برنامه make و فلگ های کامپایلر آشنا شدیم. در قسمت بعدی با نحوه کار کامپایلر در پشت پرده آشنا میشویم.