برنامه نویسی C در سیستم عامل GNU - قسمت اول

(7226 مجموع کلمات موجود در متن)
(15498 بار مطالعه شده است)  نسخه چاپی [1]

نام مقاله : برنامه نویسی به زبان C در سیستم عامل GNU - قسمت اول
نویسنده : مَهدی رسولی [2]
ویرایشگر: نوید
نسخه : ۱.۰
آخرین تغییر : ۱۳ بهمن ۱۳۸۵





مقدمه
1- هدف

به آموزش GNU C خوش آمدید. هدف از نوشتن این مقاله آموزش نوشتن نرم افزار به کمک زبان برنامه نویسی C به کاربران سیستم‌های GNU است. اصولا این مقاله به عنوان خود آموز برای افراد مبتدی نوشته شده امابرای استفاده به عنوان مرجع توسط کاربران با تجربه نیز قابل استفاده است.
مطالب پایه‌ای در چند فصل اول شرح داده شده اند. کاربران مبتدی باید به دقت آنها را مطالعه کنند اما افراد با تجربه می توانند به صورت سطحی از کنار آنها بگذرند.تمام اطلاعات در اینجا وجود دارد و به هیچ گونه اطلاعات قبلی در مورد برنامه نویسی نیاز نیست.
فرض بر این است که خواننده به یک سیستم عامل GNUای دسترسی دارد. اگر چه هدف اصلی کاربران GNU هستند اما مطالب این کتاب تا ۹۸ درصد برای کاربران - Open BSD Free BSD یا Net BSD نیز قابل استفاده است. تمام فرمان‌ها در کنار نمونه‌های برنامه نویسی ذکر شده اند با این حال آشنایی مختصر با پوسته (خط فرمان یا ترمینال) مفید خواهد بود. شما تنها به مهارت در استفاده از یک ویرایشگر متن احتیاج دارید. هر ویرایشگری قابل استفاده خواهد بود. GNU Emacs یک نمونه بسیار خوب برای برنامه نویسان است. این برنامه به مدت بیش از 20 سال است که توسعه می یابد و دارای صدها خصیصه مفید می باشد. GNU Nano یکی دیگر از ویرایشگرهای متن مفید و ساده است که شما می توانید از آن استفاده کنید. برخی برنامه نویسان مایل به استفاده از vi هستند. اگر شما از قبل یک ویرایشگر محبوب دارید می توانید از آن استفاده کنید. همچنین ویرایشگر‌های گرافیکی نظیر Anjuta یا KDevelop برای برنامه نویسان وجود دارند اما اکثر برنامه نویسان ویرایشگر‌های محیط‌های متنی را ترجیح می دهند. (Anjuta و KDevelope و نیز GNU Emacs بیش از یک ویرایشگر متن هستند و آن‌ها را IDE نیز می‌نامند که مخفف Integrated Development Environment است. به معنی محیط توسعه‌ی مجتمع.)

2- مفاد این متن

مطالب این مقاله می توانند به دو بخش تقسیم شوند : الف. هسته زبان سی و ب. توابع استاندارد ارایه شده برای برنامه نویسان. این توابع توسط کتابخانه توابع سی یا GNU libc فراهم شده اند که بخشی از هر سیستتم GNU/Linux می باشد. هیچ کدام از این دو بخش بدون دیگری استفاده نمی‌شود اما در این مقاله در شروع تمر کز بر روی هسته زبان C و در بخش‌های آخر بحث‌های بیشتری در مورد libc خواهد بود. سازماندهی مطالب به گونه‌ای است تا آموزش برنامه نویسی C در یک حالت صعودی انجام شود به گونه‌ای که مطالب هر فصل بر روی فصل قبلی بنا می شود. برخی جنبه‌های هسته زبان برای کاربران با تجربه کاربرد دارند بنابراین در فصل‌های پایانی ذکر خواهند شد. زبان C به خودی خود می تواند ساختار‌های تصمیم گیری و تکرار دستورات را ایجاد کند و ذخیره سازی داده‌ها و محاسبات ریاضی را انجام دهد. با همین اهمیت یک روش برای استفاده از توابع خارجی نظیر libc را فراهم میکند. libc توابعی برای کارهای نظیر خواندن و نوشتن فایل‌ها - دسته بندی و جست و جوی داده - دریافت ورودی برای کاربر و نمایش داده برای او - ارتیاط از طریق شبکه - ساخت برنامه‌های قابل ترجمه و غیره فراهم می‌کند.

3-چرا زبان برنامه نویسیC برای آموزش؟

زبان برنامه نویسی ‏C استاندارد است. C زبان استاندارد برنامه نویسی سیستم‌های بر پایه GNU و BSD است. اغلب این سیستم عامل‌ها به همراه برنامه‌های کاربردی که بر روی آنها اجرا می شوند به زبان C نوشته شده اند. C بیش از سی سال پیش برای نوشتن سیستم‌های عامل و برنامه‌های کاربردی شروع به توسعه یافت. C کوچک است. طراحی قابل بسط به آن این امکان را داد تا به همراه صنعت کامپیوتر توسعه پیدا کند. به دلیل قدمت و محبوبیت C زبانی دارای پشتیبانی بسیار خوب است. ابزارهای زیادی به وجود آمده اند تا برنامه نویسی C را آسان تر کنند . و این ابزار‌ها غالبا بسیار کامل و استاندارد هستند. غریب به اتفاق نرم افزارهایی که ما در این مقاله از آنها استفاده خواهیم کرد با C نوشته شده‌اند.

4- چرا استفاده از سیستم عامل GNU ؟

سیستم عامل GNU/Linux یک سیستم عامل شبه Unix است که بیش از بیست سال پیش شروع به توسعه کرد. شروع توسعه‌ی این سیستم عامل پرژه‌ی GNU است که ریچارد استالمن آن را برای فراهم آوردن آزادی نرم‌افزارها ایجاد کرد. پس از مدتی با فراهم شدن هسته‌ای به نام Linux از سوی لینوس ترووالدز سیستم عامل GNU/Linux شروع به کار نمود. نرم‌افزارهای مورد استفاده در سیستم GNU و سیستم عامل GNU/Linux به دلیل آزاد بودن (و متعاقبا اوپن سورس بودن) نرم افزار‌هایی با پایداری و قابلیت اطمینان و منطبق بر استانداردها هستند. اغلب سیستم‌های GNU از Linux به عنوان هسته استفاده می کنند. این سیستم‌ها غالبا به عنوان سیستم‌های GNU/Linux شناخته می شوند. (برای دریافت اطلاعات بیشتر می‌تونید مقاله‌ی لینوکس چیست [3] را در همین سایت مطالعه کنید.)

5- چرا نرم افزار آزاد؟

مهم‌ترین مطلب درباره‌ی GNU فراهم آوردن نرم‌افزارهایی آزاد است؛ یک نرم افزار زمانی یک نرم افزار آزاد است که چهار شرط را برای کاربران فراهم کند :
۰- آزادی برای اجرای برنامه برای هر هدفی و استفاده از آن در هر زمینه‌ای.
۱-آزادی درمطالعه درباره‌ی نحوه‌ی کار یک برنامه.(در دسترس بودن سورس کد پیش شرط این موضوع است)
۲-آزادی در توزیع مجدد برنامه و یا کپی آن برای همسایگان.
۳-آزادی برای توسعه و بهبود و تغییر برنامه و منتشر کردن دوباره‌ی برنامه. (در دسترس بودن سورس کد پیش شرط این موضوع است)

نرم افزار‌هایی که آزاد نیستند نرم افزار دارای حق مالکیت (یا انحصاری) نامیده می شوند، چرا که یک نفر ادعای مالکیت آنها را می کند و دیگران را از به اشتراگ گذاری و ایجاد تغییر در آن منع می نماید. از دیدگاه اخلاقی نوشتن نرم افزار آزاد راهی اجتماعی تر است. نرم افزار آزاد با اجازه دادن به کاربرانش برای کمک به خود از طریق ایجاد تغییرات دلخواه در نرم افزار (یا استفاده از فردی دیگر برای ایجاد تغییرات ) آنها را قدرتمند می سازند. آن به افراد اجازه می دهد تا از طریق به اشتراک گذاردن نرم افزار با همسایگانشان به آنها کمک کنند. نرم افرار انحصاری بر عکس عمل می کند : آن با گفتن این نکته به افراد که پاسخ مثبت دادن به تقاضای کمک مردم جرم است به اشتراک گذاری نرم افزار را غیر قانونی می سازد. در حالیکه نرم افزار آزاد به افراد اجازه می دهد تا با پخش نسخه‌های بهبود یافته نرم افزار به اجتماع خود کمک کنند.
نرم افزار آزاد همچنین بر ضد افراد فقیر یا افراد کشور‌های در حال توسعه موضع نمی گیرد.با اعطای تمام آزادیهای بالا به آنها اجازه می دهدتا بدون اجبار برای پرداخت مبالغ غیر ممکن پول برای حق امتیاز نرم افزار از کامپیوتر استفاده کنند. در نهایت برتری‌های فنی نیز وجود دارد. نرم افزار آزاد فارغ از دسیسه‌های بازاریابی است.آن خود را برای مجبور کردن کاربران به خرید قطعه‌های اضافی برنامه محدود نمی‌کند. هر قطعه از GNU طوری طراحی شده که تا حد ممکن مفید باشد. به عنوان یک برنامه نویس شما از همان نرم افزار برنامه نویسی C استفاده می کنید که در پروژه‌های بزرگ استفاده می شود.
نر افزار‌های انحصاری تنها در یک شکل قابل خواندن برای ماشین توزیع می شوند. این یعنی کاربر نمی تواند از آنچه درون نرم افزار اتفاق می افتد اطلاع یابد.در مقابل نرم افزار آزاد باید به همراه کد منبع خود در یک فرمت قابل خواندن برای انسان منتشر شود. به عنوان یک برنامه نویس شما می توانید کدهای هر قطعه از نرم افزار ازاد را که مایل باشید مطالعه کنید. اگر خطایی در برنامه وجود داشته باشد شما می توانید خودتان آنرا رفع کنید.
این آزادی در رفع خطاها و اضافه ساختن امکانات چیزی است که نرم افزار GNU را عالی می سازد. همه کدها برای بازبینی در دسترس اند.
نرم افزار آزاد قصد تغییر جهان برای بهتر شدن را دارد.


بخش اول : دیباچه‌ای بر C
1.1 زبان برنامه نویسی چیست؟

یک زبان برنامه نویسی قالبی برای طرح ریزی برای اجرای موارد سفارش داده شده توسط کامپیوتر تعریف می‌کند. زبان‌های برنامه نویسی به سه دسته تقسیم می شوند. ۱.زبان‌های ترجمه‌ای ۲. زبان‌های کامپایل شده و ۳.زبان ماشین. از این میان تنها زبان ماشین به طور مستقیم توسط کامپیوتر قابل فهم است.
یک زبان ماشین مجموعه‌ای از راهنمایی‌ها(instructions) است که CPU کامپیوتر (واحد پردازشگر مرکزی) می‌فهمد. تمام راهنمایی‌ها و اطلاعات توسط اعداد نمایش داده می شوند. خیلی سریع برای کامپیوتر و خیلی سخت برای مغز انسان برای خواندن و نوشتن آنها. برای آسان تر ساختن وظیفه برنامه نویسی کامپیوتر مردم زبان آسانتری را ساختند که Assembly نامیده می شد. یک زبان Assembly نامهای متنی برای دستورات در دسترس زبان ماشین فراهم میکند. این مطلب در کنار این واقعیت که زبان اسمبلی به برنامه نویسان اجازه اضافه کرن فاصله‌ها و تب‌ها را در کدها می دهد زبان Assembly را برای برنامه نویسی بسیار راحت می سازد. برنامه‌های Assembly می توانند برای ترجمه به زبان ماشین به منظور فهم CPU به یک Assembler سپرده شوند. استفاده از زبان‌های Assembly خیلی سریع گسترش یافت. آنها به عنوان زبانهای نسل دوم شناخته می شدند. اما هنوز هم دو مشکل وجود داشت، مشکل اول آن بود که هر دستور Assembly تنها یک وظیفه خیلی ابتدایی نظیر جمع دو عدد و یا بارگذاری یک مقدار از حافظه را انجام می داد، استفاده از این دستورات کوچک واقعا ملالت آور بود. مشکل دوم بزرگتر بود، هر کدام از برنامه‌های نوشته شده به Assembly به نوع خاصی از CPU وابسته بود، به عبارت دیگر به یک معماری خاص از پردازنده‌های مرکزی وابسطه بودند. هر نوع از CPU زبان ماشین مخصوص به خود را داشت، بنابراین زبان Assembly مخصوص به خود را داشت. کار مهم بعدی طراحی زبانی بود که به زبان ماشین انواع زیادی از CPU قابل ترجمه باشد. این زبانهای جدید وابسته به ماشین زبانهای نسل سوم یا زبانهای سطح بالا نامیده می شوند. این زبانها که برای آسان خوانده شدن طراحی شده بودند از کلمات انگلیسی - سمبل‌های پایه‌ای ریاضی و علایم نقطه گذاری تشکیل می شدند. این زبانها به عبارات ساده اجازه می دهند تا به طور مختصر بیان شوند به عنوام نمونه جمع دو عدد و ذخیره سازی حاصل در حافظه می تواند به صورت زیر بیان شود:

data = 10 + 200;

که بر عبارت زیر ارجحیت دارد:

Load R1, 10
Load R2, 200
Addi R1, R2
Store R2, L1
‏1.2 زبان C چیست ؟

سپس ابزاری که کامپایلر نامیده می شود برای تبدیل کدهای سطح بالا به زبان ماشین استفاده می شود. یک برنامه می‌ تواند به زبان C نوشته شده و سپس برای هر کامپیوتری کامپایل شود. درگیری با جزییات سخت افزاری بر عهده کامپایلر است. برای مقایسه برتری زبان C بر Assembly به یک برنامه کوچک که در هر دو زبان نوشته شده نگاه کنید:
نمونه 1.1 C در مقایسه با Assembly :

.section  .rodata
.LC0:
          .string   "Tax Due: %d "
          .text
          .align 2
.globl main
          .type     main,@function
main:
          pushl     %ebp
          movl      %esp, %ebp
          subl      $24, %esp
          andl      $-16, %esp
          movl      $0, %eax
          subl      %eax, %esp
          movl      $1000, %eax
          movl      $400, %edx
          movl      $0x3e6147ae, -12(%ebp)
          subl      %edx, %eax
          pushl     %eax
          fildl     (%esp)
          leal      4(%esp), %esp
          fmuls     -12(%ebp)
          fnstcw    -18(%ebp)
          movw      -18(%ebp), %ax
          movb      $12, %ah
          movw      %ax, -20(%ebp)
          fldcw     -20(%ebp)
          fistpl    -16(%ebp)
          fldcw     -18(%ebp)
          subl      $8, %esp
          pushl     -16(%ebp)
          pushl     $.LC0
          call      printf
          addl      $16, %esp
          movl      $1, %eax
          leave
          ret
.Lfe1:
          .size     main,.Lfe1-main

همان برنامه این‌بار که اینبار به زبان C نوشته شده است :

#include 
 
int
main()
{
  int wages = 1000;
  int tax_allowance = 400;
  float tax_rate = 0.22;
  int tax_due;
 
  tax_due = (wages - tax_allowance) * tax_rate;
 
  printf("Tax Due: %d euro
", tax_due);
 
  return 0;
}
 

بدون شناخت از زبان C شما کدام برنامه را برای خواندن آسانتر می دانید؟ خروجی هر دو برنامه مشابه است :

 "Tax Due: 131 euro"

کد Assembly نشان داده شده که در مجموعه راهنمایی 80386 نوشته شده در ماشینی که از مجموعه راهنمایی دیگری استفاده می کند کار نخواهد کرد . اما کد C می تواند عملا برای هر کامپیوتر با هر معماری پردازشگری کامپایل شود.

1.3 ابزارهای برنامه نویسی

‏سیستم‌های GNU به همراه کامپایلری به نام gcc ارایه می شود. gcc از ابتدا مخفف GNU C Compiler بود ولی پس از مدتی که قابلیت کامپایل زبان‌های دیگری غیر از C به آن افزوده شد نام آن را GNU Compiler Colection خطاب می‌کنند. پدید آورنده‌ی اصلی GCC ریچارد استالمن، بناینگذار پروژه GNU است. نخستین نسخه GCC در سال ۱۹۸۷ انتشار یافت که یک پیشرفت مهم و اساسی در پیشبرد اهداف GNU Project محسوب می‌شد زیرا محصول جدید اولین کامپایلر بهینه سازی شده قابل حمل ANSI C به عنوان یک نرم افزار آزاد محسوب می شد. در سال ۱۹۹۲ نسخه 2.0 کامپایلر GCC عرضه شد. نسخه جدید قابلیت کامپایل کدهای ++C را نیز داشت.
در سال ۱۹۹۷ یک انشعاب آزمایشی در GCC به نام EGCC به منظور بهینه سازی کامپیایلر و پشتیبانی کامل تر از ++C ایجاد شد. در ادامه EGCC به عنوان نسل بعدی کامپایلر GCC پذیرفته شد و تکامل آن باعث انتشار نسخه سوم GCC در سال ۲۰۰۴ گردید. چهارمین نسخه از کامپایلر GCC در سال ۲۰۰۵ عرضه شد. برای اطمینان از اینکه gccرا نصب کرده‌اید یا خیر دستورات زیر را وارد کنید :

ciaran@pooh:~/$ gcc --version 4.1.1 $ciaran@pooh:~/

نسخه‌ای از gcc که شما استفاده می کنید ممکن است متفاوت باشد. هر چیزی شبیه این از قبیل 3.4.6 یا 4.1.1 مناسب است. اگر پیغام خطای " command not found" را دریافت می کنید، شما gcc را نصب نکرده‌اید. اگر لینوکستان را از روی cd نصب کرده‌اید می توانید gcc را در آن پیدا کنید. اگر شما نمی‌دانید چگونه باید gcc را در سیستم خود نصب کنید می‌توانید از طریق انجمن‌های مختلف موجود در اینترنت اقدام نمایید. کافیست در این انجمن‌ها پرسش خود را بپرسید تا کسانی اطلاعاتی در این زمینه دارند به شما کمک کنند. (برای نمونه می‌توانید به انجمن‌های سایت گنوایران. ارگ مراجعه کنید.)

1.4 معرفی کامپایلر gcc

بسیار خوب، می خواهیم کامپایل کردن یک تکه کوچک کد C را از طریق gcc به شما نشان دهیم. اینجا هدف آموزش نحوه استفاده از gcc است بنابر این در این بخش به شرح سازوکار کد C نمی‌پردازیم. در نمونه ۱.۳ کوچکترین قطعه کد C که gcc قادر به کامپایل آن است را می بینید. این کد هیچ کاری انجام نمی دهد.
نمونه 1.3 tiny.c

main()
{
}

این قطعه کد را در ویرایشگر متن خود تایپ و با نام tiny.c ذخیره کنید. شما می توانید هر نام دیگری را نیز که به پسوند c. ختم می شود انتخاب کنید. این پسوندی است که برای سورس کدهای نوشته شده با C استفاده می شود. gcc برای کامپایل یک برنامه صحت این پسوند را چک می‌کند. با در اختیار داشتن یک فایل ذخیره شده حالا می توانید به وسیله دستور زیر آنرا کامپایل کنید:
کامپایل برنامه

ciaran@pooh:~/$ gcc tiny.c $ciaran@pooh:~/

در صورتیکه که‌این فرمان با موفقیت انجام شود بدون پیغام خروجی خواهد بود. در صورتیکه هر گونه پیغام خطایی را دریافت کردید باید صحت برنامه خود را چک کنید. در صورتیکه فرض کنیم شما این برنامه هشت کاراکتری را درست نوشته باشید باید فایلی به نام a.out در دایرکتوری شما ایجاد شود. این برنامه زبان ماشینی است که از کدهای بالا ساخته شده است. در صورتیکه آنرا اجرا کنید خواهید دید که در واقع هیچ فعالیتی انجام نمی دهد. نامگذاریa.out دلایل تاریخی دارد، اما مخفف output Assembler می‌باشد.
اگر چه gcc این کدها را کامپایل کرد اما این کدها کامل نیستند اگر شما اخطار‌های gcc را فعال کنید به شما گفته خواهد شد چه کمبود‌هایی وجود دارد. با اضافه کردن گزینه‌ی Wall- به فرمان کامپایل می‌توانیماخطار‌های gcc را فعال می کنیم:

فعال کردن نمایش اخطارها

ciaran@pooh:~/$ gcc -Wall tiny.c tiny.c:2: warning: return-type defaults to `int' tiny.c: In function `main': tiny.c:3: warning: control reaches end of non-void function ciaran@pooh:~/$

دلیل نمایش داده شدن این پیغام‌ها کامل نبودن برنامه‌ی نوشته شده توسز ماست. برای رهایی از این پیغام‌ها باید با افزودن سازوکارهای جدید برنامه‌ای کامل‌تر ایجاد کنیم. در اینجا با افزودن دو سطر جدید به برنامه، آن را به کوتاهترین برنامه معتبر C تبدیل می‌کنیم:
نمونه 2.3 tiny2.c

int main() { return 0; }

حالا برنامه را با گزینهWall- کامپایل می کنیم و شاهد این خواهید بود که پیام خطایی نمایش داده نمی‌شود. گزینه‌ی مفید دیگر o filename- است که نام فایل خروجی را ( به جای a.out) مشخص می‌کند.

ciaran@pooh:~/$ gcc -Wall -o tiny-program tiny2.c ciaran@pooh:~/$ ls tiny2.c tiny-program ciaran@pooh:~/$ ./tiny-program ciaran@pooh:~/$

1.5 چه کسی c معتبر را تعریف می کند؟

برای شما به عنوان یک برنامه نویس C معتبر توسط کامپایلر تعریف می شود. لهجه‌های مختلف زیادی از C وجود دارد. (یا بهتر است بگوییم انواع مختلفی از زبان C موجود هستند.) خوشبختانه اغلب این انواع بسیار به یکدیگر شباهت دارند. همچنین زبانهای دیگری نیز وجود دارند که بر پایه C ساخته شده اند مانند Objective C و ++C. این زبان‌ها در ظاهر بسیار شبیه C هستند اما کاربردی متمایز دارند. gcc خیلی از لهجه‌های زبان C را به خوبی خیلی از زبان‌های دیگر از قبیل ++C و Obcetive C می فهمد. ( انواع C در IBM [4])

1.5.1 Keringhan و Ritchie

زبان ‏C توسط Dennis Ritchie بین سالهای ۱۹۶۹ تا ۱۹۷۳ ابداع شد؛ در سال ۱۹۷۸ دنیس ریچی به همراه Brian Kernighan یک کتاب آموزشی بسیار خوب برای C با نام "The C programming language"منتشر کرد. این کتاب در واقع اولین تعریف رسمی از این زبان بود و از آنجا که نوع اصلی C محسوب می شود گاهی اوقات به آن C سنتی می گویند. متاسفانه‌این کتاب بسیاری از جنبه‌های این زبان را تعریف نشده باقی گذاشت. بنابر این افرادی که کامپایلر‌ها را می نوشتند مجبور بودند خود در مورد چگونگی رفتار با این جنبه‌ها تصمیم گیری کنند. نتیجه‌ی ‌این رفتار وابستگی شدید C و واکنش آن به کدها به نوع کامپایلر مورد استفاده بود. ممکن بود کدی که در یک کامپایلر نتیجه‌ای مطلوب می‌دهد در کامپایلر دیگری نتایج متفاوتی را در بر داشته باشد. استفاده از این لهجه مدت زیادی طول نکشید. gcc تنها برای کامپایل برنامه‌های خیلی قدیمی از آن پشتیبانی می کند و ما تنها به خاطر مقاصد تاریخی به آن اشاره کردیم.

‏1.5.2نسخه‌ی ISO C

در سال ۱۹۸۳ موسسه استاندارد ملی آمریکا (ANSI) کمیته‌ای را به منظور تدوین یک استاندارد صحیح و رفع برخی کاستی‌ها ی زبان C تشکیل داد. کار تدوین این استاندارد در سال ۱۹۸۹ به پایان رسید و مورد پذیرش سازمان بین المللی استاندارد یا (ISO) نیز قرار گرفت. این لهجه جدید با نام C89 شناخته شد. همچنین از آن به عنوان ISO C و ANSI C نیز یاد می شود. gcc یکی از سازگارترین کامپایلر‌های موجود با این لهجه است.

1.5.3 C99

کمیته ANSI C جلسات بسیار کمی را برای ارتقای این زبان تشکیل می دهد. آخرین استاندارد ارتقا یافته در سال ۱۹۹۹ عر ضه شد که با نام C99 شناخته می شود. تاکنون کامپایلر‌های بسیار کمی به طور کامل از C99 پشتیبانی می کنند زیرا ایجاد تغییرات در یکی از مهمترین نرم افزار‌های سیستم عامل کار زمان گیری است. تا زمان نگارش این مقاله پشتیبانی gcc از C99 تا حد قابل توجهی کامل شده است اما توسعه دهندگان هنوز مشغول کار بر روی آن هستند.

1.5.4 GNU C

‏GNU C بسیار شبیه C89 است اما دارای برخی خصیصه‌های جدید از C99 و برخی امکانات فرعی اضافه (extension) دیگر است. امکانات فرعی برای رفع برخی اشکالاتی که C99 راه حل مناسبی برای آنها ارایه نکرده توسط توسعه دهندگان ارایه شده اند. GNU C نوع پیش فرض gcc و نیز لهجه‌ایست که ما در این مقاله به کار خواهیم برد. ما نهایت تلاش خود را خواهیم کرد تا در مواقعی که از امکانات فرعی GNU C استفاده می کنیم آنها را مشخص کنیم هر چند به طور کلی استفاده کامل از GNU C بهتر است زیرا استفاده از ISO C باعث محدود شدن برنامه‌های شما به استفاده از جنبه‌های مشترک می گرددو کابرد آنها را محدود به موارد معینی می سازد.

1.5.5 انتخاب یک نوع C

در صورتیکه می‌خواهید لهجه‌ای غیر از لهجه پیش فرض انتخاب کنید می توانید با گزینه‌ی =std- انتخاب خود را مشخص کنید. به دنبال این گزینه‌ می‌توانید یکی از گزینه‌هایc89 ، c99 GNU89 و GNU99 را وارد کنید. GNU89 در حال حاظر گزینه پیش فرض است تا زمانی که پشتیبانی از c99 تکمیل شود. در آن صورت GNU99 گزینه پیش فرض خواهد شد. در هر صورت تغییرات چندان قابل توجه نخواهد بود.

1.5.6 آینده استانداردها

امکانات فرعی اضافه از قبیل آنهایی که توسط gcc اضافه می شوند منابع الهام اصلی ISO برای استاندارد‌های جدید C هستند. زمانی که گروه ANSI C مشاهده می کنند تعداد زیادی از کامپایلر‌ها یکی از امکانات فرعی اضافه را به کار می گیرند آنها لزوم وجود آن امکان را بررسی می نمایند و در صورتیکه آنرا مفید تشخیص دهند یک را استاندارد برای به کار گیری آن ارایه می دهند. برخی از امکانات فرعی اضافه شده توسط gcc ممکن است در آینده به صورت استاندارد در آیند و برخی دیگر ممکن است اینگونه نباشند.

1.6 خاتمه

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


بخش دوم : توابع در زبان C
2.1 توابع چه هستند؟

توابع بلوک‌های ساختاری برنامه‌های C هستند. اکثریت برنامه‌های C از بلوک‌هایی از کد که تابع(function) نامیده می شوند ساخته می شوند. وقتی یک برنامه را می نویسید شما توابع زیادی را برای انجام وظایفی که احتیاج دارید ایجاد خواهید کرد. علاوه بر این تعداد زیادی از وظایف عمومی از قبیل نمایش یک متن بر روی صفحه نمایش وجود دارند که مورد نیاز اکثر برنامه نویسان هستند. به جای اینکه هر برنامه نویس مجبور باشد در این زمینه سرمایه گذاری مجددی صورت دهد سیستم‌های GNU به همراه کتابخانه(library)‌هایی از توابع پیش ساخته برای انجام بسیاری از این وظایف عرضه می شوند. در طول سالها هزاران مورد از چنین توابعی بر روی هم جمع شده اند. در غیر این صورت اگر شما قصد نوشتن برنامه‌ای برای بازی BINGO داشتید مجبور بودید شخصا توابع مخصوص برنامه را بنویسید امااکنون در می یابید که افراد دیگر توابعی برای تولید اعداد تصادفی – نمایش اعداد بر روی صفحه نمایش – دریافت اعداد ورودی از بازیکن و موارد دیگر نوشته اند.
هر برنامه C ملزم به داشتن تابعی به نام ()main است. اجرای برنامه از این تابع شروع می شود. می توان تمامی کدهای برنامه را در تابع ()main قرار داد اما روش مرسوم تر تقسیم برنامه به چندین تابع کوچک است. به عنوان اولین قطعه کد مفید در این مقاله به یک نمونه کلاسیک نگاه می اندازیم. سپس از کامپایل و اجرا برنامه یک پیام ساده روی صفحه نمایش شما چاپ می‌کند. برنامه تابعی به نام ()main را تعریف (define) و تابعی به نام ()printf را فراخوانی (call) می‌کند. ()prinf تابعی است که توسط کتابخانه ابزار ورودی/خروجی استاندارد (Standard Device Input/Output library) فراهم می شود که‌این کتابخانه به همراه هر سیستم GNU وجود دارد. متن برنامه کوچک ما به صورت زیر است:

نمونه 2.1 hello.c

#include 
 
int
main()
{
  printf("hello, world");
 
  return 0;
}

حالا برنامه را کامپایل و اجرا کنید. اگر همه چیز درست باشد عبارت “hello, world” بر روی ترمینال شما (ابزار خروجی استاندارد ) نمایش داده خواهد شد. در صورتیکه فرامین مربوط به کامپایل و اجرای برنامه را فراموش کرده‌اید آنها به صورت زیر هستند :
فرامین کامپایل و اجرای برنامه

ciaran@pooh:~/$ gcc -Wall -o hello hello.c ciaran@pooh:~/$ ./hello hello, world ciaran@pooh:~/$

اگر شما هرگونه پیام خطا و یا اخطار را مشاهده می کنید دقت کنید که کدهای شما دقیقا مطابق کدهای این کتاب باشد. هر پیام خطایی که دریافت کنید سطری را که در آن مرتکب اشتباه شده‌اید به شما اعلام می‌کند. در صورتیکه کدها را صحیح تایپ کرده باشید چنین پیام‌هایی را دریافت نخواهید کرد.

2.2 یک تشریح سطر به سطر

حالا به طور سریع کاری را که هر سطر انجام می دهد تشریح می کنیم.در صورتیکه برخی از سطر‌ها برای شما مبهم است نگران نباشید. در آینده نمونه‌های بسیار زیادی را انجام خواهیم داد. سطر <include></include>
این سطر به gcc می گوید از کتابخانه ابزار ورودی/خروجی استاندارد اطلاعاتی را در مورد چگونگی استفاده از توابع برداشت کند. به طور معمول ابزار ورودی استاندارد صفحه کلید و ابزار خروجی استاندارد صفحه نمایش است. این کتابخانه به طور گسترده مورد استفاده قرار می گیرد و ما در این مقاله با توابع بسیار زیادی از آن سروکار خواهیم داشت.

int main()

این دو سطر تعریف تابع ()main را آغاز می کنند. در مورد سطر اول از این دو سطر بعدا توضیحات بیشتری خواهیم داد.

{
آکولاد باز نشانه شروع یک بلوک کد است. تمام کدهای بین آکولاد باز و بسته جزیی از تابع ()main هستند.
printf("hello, world ");
این سطر در واقع یک فراخوانی تابع (function call) است. تابع از قبل برای شما تعریف شده است. وقتی شما تابع ()printf را فرا می خوانید باید یک نشانوند(Argument)برای آن ذکر کنید تا به آن بگویید چه چیزی را نمایش دهد.
return 0;
دستور return به اجرای تابع ()main خاتمه می دهد. هیچ دستور دیگری بعد از این سطر اجرا نخواهد شد. با پایان یافتن تابع ()main برنامه شما خاتمه می یابد. زمانی که یک تابع به پایان می رسد می تواند مقداری را به محلی که از آنجا فراخوانی شده بازگرداند. این کار با قراردادن یک مقدار پس از return حاصل می شود.تابع ()main همواره یک مقدار صحیح (یک عدد مثبت یا منفی بدون اعشار) را باز می گرداند.ما با مقدم ساختن تعریف ()main با int به کامپایلر می فهمانیم که منتظر چنین چیزی باشد. قرار بر این است که درصورت اجرای بدون اشکال تابع ()main مقدار بازگشتی برابر صفر باشد.
{
آکولاد بسته نشانه پایان بلوک کدی است که تابع ()main را می سازد. دو سطری که بدنه تابع ()main را می سازند با نام تقریر (statement) شناخته می شوند. به صورت دقیقتر این‌ها تقریرات ساده (simple statements) هستند (در مقابل تقریرات مرکب (compound statements) که در بخش چهار به آنها می رسیم). (لینک به بخش چهار-- یادداشت ۴) تقریرات در زبان C به منزله جملات برای زبانهای گفتاری هستند. در انتهای هر تقریر ساده یک نقطه-ویرگول (semi-colon) قرار می گیرد. اضافه نمودن خطوط خالی در برنامه اختیاری است.C هیچگونه نیازی به آنها ندارد اما استفاده از آنها باعث خوانایی برنامه می شود. متذکر شدیم که تابع ()main ما مقدار صفر را باز می گرداند. اغلب توابع مقدار بازگشتی خود را به برنامه بازمی گردانند در حالیکه تابع ()main مقدار بازگشتی خود را که نشانه پایان برنامه است برای پوسته ارسال می‌کند. مقدار بازگشتی برنامه توسط پوسته ذخیره می شود. درصورتیکه مایل به مشاهده آن هستید از دستورات زیر استفاده کنید:

ciaran@pooh:~/$ gcc -Wall -o hello hello.c ciaran@pooh:~/$ ./hello hello, world ciaran@pooh:~/$ echo $? 0 ciaran@pooh:~/$

2.3 توضیحات

توضیحات یا Comment‌ها راهی برای اضافه نمودن متون توضیحی در برنامه هستند. آنها توسط کامپایلر نادیده گرفته می شوند بنابراین هیچ تاثیری بر روی برنامه شما ندارند. هر چنداین کار حجم برنامه شما را افزایش می دهد اما شما پی خواهید برد که استفاده از Comment‌ها وسیله مفیدی است تا به شما یادآوری کند مشغول انجام چه کاری هستید.در نمونه‌های این کتاب ما Comment‌ها را برای توضیح آنچه در حال انجام است به کار می بریم.با دو روش میتوانید یک Comment را وارد برنامه خود سازید:عادی ترین روش اینست که در شروع و انتهای متن توضیحی خود به ترتیب از /* و */ استفاده کنید. توضیحات در این روش می توانند از چندین سطر تشکیل شوند. روش دوم استفاده از // درابتدای سطر است که محتویات بعد از خود تا پایان سطر جاری را به متن توضیحی مبدل می سازد.
در این جا برنامه hello, world ما به همراه متون توضیحی آورده شده است:
نمونه 2.2 hello2.c

/* The purpose of this program is to
 * display some text to the screen
 * and then exit.
 */
 
#include 
 
int
main()
{
  /* printf() displays a text string */
  printf("hello, world");
 
  return 0;  //zero indicates there were no errors
}

پس از کامپایل از لحاظ اجرایی این کدها مشابه کدهای نمونه قبل هستند. خطوط 2 و 3 توضیحات بالا با یک ستاره آغاز می شوند . این کار اگر چه لازم نیست اما این نکته که توضیحات در چهار سطر ادامه دارد را روشن می سازد.

2.1 ساختن توابع شخصی

در نمونه قبلی ما تنها بک تابع معرفی کردیم. برای اضافه کردن توابع دیگر به طور کلی شما باید دو کار انجام دهید: ابتدا باید به همان صورت که برای تابع ()main انجام دادیم آنها را تعریف کنیم. کار دیگری که باید انجام دهیم اعلان (declare) توابع است. اعلان یک تابع به منزله‌این است که به gcc بگوییم تا منتظر آن تابع باشد. ما مجبور به اعلان تابع ()main نیستسم زیرا آن یک تابع مخصوص است و gcc می داند که باید منتظر آن باشد. نامی که به تابع می‌دهیم باید در هر دو جنبه اعلان و تعریف ظاهر شود.
نام تابع می تواند از حروف الفبا یعنی کاراکترهای A تا Z و a تا z و نیز ارقام 0 تا 9 و کاراکتر خط زیر(underscore) یعنی "_" تشکیل شود. این کاراکتر‌ها به هر ترتیبی می توانند کنار هم قرار بگیرند اما حرف نخست نام تابع نمی تواند عدد باشد. زبان C حساس به بزرگی و کوچکی متن (case-sensitive) است بنابرین My_Function کاملا با my_function متمایز است. نام هر تابع باید متمایز بوده و طول آن از یک تا 36 کاراکتر مجاز است. به همراه نام باید به هرتابع یک نوع و یک بلوک کد اختصاص دهید. نوع تابع برای کامپایلر مشخص می سازد که مقدار بازگشتی تابع چگونه است. تابع می تواند بدون مقدار بازگشتی باشد. مقدار بازگشتی تابع ()printf یک عدد صحیح و برابر تعداد کاراکترهای است که بر روی ترمینال نمایش داده است. این اطلاعات برای ما مهم نیستند بنابرین آنها را در برنامه خود نادیده می گیریم. در بخش بعدی در مورد جزییات انواع داده‌ای صحبت خواهیم کرد و سپس به تفصیل مقادیر بازگشتی توابع خواهیم پرداخت.
در اینجا برنامه‌ای را داریم که ۳ تابع را تعریف می کند:
نمونه 2.3 three_functions.c

#include 
/* function declarations */
int first_function(void);
int goodbye(void);
int
main()            // function definition
{
  printf("the program begins... ");
  first_function();
  goodbye();
 
  return 0;
}
int
first_function()  // function definition
{
  /* this function does nothing */
  return 0;
}
int
goodbye()         // function definition
{
  printf("...and the program ends. ");
  return 0;
}    

در نمونه بالا ما تابع ()first_function را نوشتیم که هیچ کاری انجام نمی دهد و نیز تابع ()goodbye که یک پیغام را در صفحه نمایش چاپ می‌کند. اعلان توابع باید قبل ار فراخوانی آنها صورت بگیرد یعنی در نمونه ما باید توابع قبل از تابع ()main اعلان می شدند. به طور کلی مرسوم است که اعلان توابع بعد از سطر‌های شامل عبارت include# و قبل ار آغاز تعریف توابع صورت می گیرد.

2.5 فایل‌های چندگانه

اجباری برای اینکه برنامه‌ها تنها در یک فایل معین نوشته شوند وجود ندارد. کدهای شما میتوانند در هر تعداد فایل که بخواهید پخش شوند. به عنوان نمونه اگر برنامه‌ای از ۴۰ تابع تشکیل شده باشد شما می توانید هر تابع را در یک فایل جداگانه قرار دهید؛ اگر چه این کار یک افراط در تکه تکه کردن برنامه است. غالبا توابع بر حسب موضوع در گروه‌هایی دسته بندی شده و در فایل‌های جداگانه قرار می گیرند. برای نمونه در صورتیکه وظیفه یک برنامه محاسبه قیمت یک پیتزا و نمایش نتیجه است شما می توانید توابع مربوط به محاسبه قیمت را در یک فایل و توابع نمایش نتایج را در فایل دیگری قرار داده و از فایل سوم برای نگهداری تابع ()main استفاده کنید. حال می توانید از فرمان زیر برای کامپایل برنامه استفاده کنید:
کامپایل برنامه تشکیل شده از سه فایل

ciaran@pooh:~/$ gcc -o pizza_program main.c prices.c display.c

یاد آوری می کنیم در صورتیکه تابعی را در prices.c تعریف و قصد فراخوانی آن را در main.c دارید باید آنرا در main.c اعلان کنید.

2.6 فایل‌های سرآیند

ادامه پیگیری اعلان توابع می تواند موجب شلوغ کاری شود. به همین دلیل فایل‌های سرآیند برای جا دادن کدهای C که شما قصد به کارگیری آنها در فایل‌های چندگانه را دارید استفاده می شوند. قبل از این شما به طور عملی از یک فایل سرآیند به نام stdio.h استفاده کردید، این فایل سرآیند شامل اعلان توابع بسیار زیادی است. از جمله شامل تابع ()printf و نیز اعلان آن است. شما نیز می توانید یک فایل سرآیند شامل اعلان توابعی که قصد به اشتراک گذاری آنها را دارید ایجاد کنید و سپس با استفاده از include# آن را در اختیار هر فایل C که به اطلاعات آن احتیاج دارد قرار دهید. تنها تفاوت موجود در این است که شما باید به جای علائم < و > نام فایل خود را بین دو "،" یا کوتیشن مارک قرار دهید. یعنی از "my_header.h" به جای استفاده کنید. برای توضیح این نکته برنامه پیتزا که قبلا به آن اشاره کردیم را خواهیم نوشت.

2.7 یک (غیر) برنامه بزرگتر

نکات کوچک برنامه نویسی که تا کنون بررسی کردیم برای نوشتن یک برنامه آراسته و تاثیر گذار کافی نیستند. برای حفظ سادگی برنامه ما تنها یک اسکلت کلی از برنامه را می نویسیم تا بدینوسیله ساختار و روش استفاده از فایل‌های سرآیند را تشریح کنیم بدون اینکه شما در باتلاق مفاهیم جدید فرو روید. در بخش سوم مقاله یک نسخه کامل از این برنامه را خواهیم نوشت. کدهای زیر می توانند کامپایل و اجرا شود اما عملیاتی برای محاسبه قیمت و یا سوال از کاربر برای وارد کردن اطلاعات انجام نخواهد داد.
نخست با فایل main.c سرو کار داریم که تنها شامل تابع ()main می شود.()main برخی از توابعی که در فایل‌های دیگر تعریف شده اند را فراخوانی خواهد نمود. متذکر می شویم که فایل main.c فاقد سطر #include می باشد زیرا از هیچ یک از توابع عضو کتابخانه ابزار ورودی/خروجی استاندارد استفاده نمی‌کند.
نمونه 2.4 main.c

#include "display.h"
#include "prices.h"
 
int
main()
{
  display_options();
  calculate_price();
  display_price();
 
  return 0;
}

در مرحله بعد به بررسی display.c می‌پردازیم. این فایل شامل دو تابع است که هر دو از طریق تابع ()main فراخوانی می شوند و ما اعلان آنها را در یک فایل سرآیند با نام display.h قرار داده‌ایم. نمونه 2.5 display.c

#include 
 
int
display_options()
{
  printf("Welcome to the pizza parlor
");
  printf("What size pizza would you like? (in inches)");
 
  return 0;
}
 
int
display_price()
{
  printf("Your pizza will cost 0.00
");
 
  return 0;
}
نمونه 2.6 display.h
/* header file just contains function declarations, an file that wants
 * to use either of these functions just has to #include this file */
int display_options(void);
int display_price(void);

و در نهایت prices.c را داریم که شامل توابعی برای دریافت داده از کاربر و محاسبه قیمت مجموع هزینه‌های پیتزا است. تنها یکی از این توابع از طریق ()main فراخوانی می شود بنابر این اعلان دو تابع دیگر در بالای همین فایل صورت می گیرد. کدهای کامل این توابع را در فصل سوم خواهیم نوشت.
نمونه 2.7 prices.c

int get_size(void);
int get_toppings(void);
 
int
calculate_price()
{
  /* insert code here.  Will call get_size() and get_toppings(). */
  return 0;
}
 
int
get_size()
{
  /* insert code here */
  return 0;
}
 
int get_toppings()
{
  /* insert code here */
  return 0;
}
نمونه 2.8 prices.h
int calculate_price(void);

حالا می توانید gcc را با دستور زیر برای کامپایل فایل‌های بالا به کار گیرید:

gcc -Wall -o pizza_program main.c prices.c display.c

این برنامه در زمان اجرا پس از نمایش یک پیغام خوش آمدگویی اعلام می کند که قیمت پیتزای شما برابر £0.00 است.

2.8 یک تابع جدید دیگر

قبل از ادامه بیایید نگاهی به یکی دیگر از توابع عضو کتابخانه ابزارهای ورودی/خروجی استاندارد بیاندازیم: ()printf. دستور چاپ قالبدار یکی از شکل‌های پیشرفته تابع ()printf است. رشته‌ای که برای ()prinf ارسال می شود می تواند شامل کاراکترهای کنترلی که دارای معانی مخصوصی هستند باشد. رفتن به سطر جدید به طور خودکار توسط ()printf صورت نمی گیرد و برای اینکار باید کاراکترهای را اضافه نمایید.

2.9 خلاصه اصول اولیه

مطالبی را که تا کنون از آنها عبور کردیم نباید چندان سخت باشند. اگر قصد کسب تجربه را دارید برنامه‌هایی مشابه که دارای چندین سطر خروجی هستند ایجاد کنید. برنامه خود را به دو تابع تقسیم کرده و آنها را در دو فایل مجزا قرار دهید. همواره در هنگام کامپایل اخطارهای gcc را فعال کنید. اخطارها خبر از مبهم بودن و یا ناکامل بودن کدهای شما می دهند.در این حالت gcc معنای صحیح آنها را حدس می زند و اغلب این کار را به درستی انجام می دهد اما شما نباید به آنها اعتماد کنید. جست و جو برای تصحیح پیغام‌های خطا به مهارت شما در استفاده از زبان کمک میکند. اغلب پیغام‌های خطا به همراه شماره سطری که مشکل در آن وجود دارد می آیند. اگر شما در آن سطر هیچگونه خطایی مشاهده نمی کنید سطر فوقانی آنرا چک کنید. در صورتیکه یک دستورالعمل ناکامل باشد gcc تا زمانی که به ابتدای دستورالعمل بعدی نرسیده متوجه وجود خطا نخواهد شد.نقطه ویرگول‌های خود را فراموش نکنید.

[قسمت دوم [5]]

  
[ بازگشت به نرم افزار‌ کاربردی [6] | صفحه اصلی بخش مقالات [7] ]
امتیاز دهی 1/10
_LINKS
  [1] https://www.gnuiran.org/index.php?name=Sections&req=viewarticle&artid=47&allpages=1&theme=Printer
  [2] http://mahdix.blogsky.com
  [3] http://www.gnuiran.org/WhatisLinux
  [4] http://www-128.ibm.com/developerworks/views/power/libraryview.jsp?search_by=everything+you+ever+wanted+to+know+about+C+types&ca=dgr-wikiaCTypesSeries
  [5] http://www.gnuiran.org/modules.php?op=modload&name=sections&file=index&req=viewarticle&artid=48
  [6] https://www.gnuiran.org/index.php?name=Sections&req=listarticles&secid=1
  [7] http://www.gnuiran.org/Articles