آموزش AVR GCC قسمت سوم

تایع:

یکی از ویژگی های مهم زبان های ساختیافته ماژولار یا پیمانه ای بودن آنهاست و این بدان معناست که هر برنامه را می توان به تعدادی برنامه فرعی کوچکتر تجزیه کرد. این برنامه های فرعی باعث می شوند :

  1. برنامه اصلی طولانی نباشد.
  2. نوشتن و آزمایش کردن یک قطعه برنامه ساده تر از یک برنامه بزرگ است.
  3. باعث جلوگیری از تکرار دستورات مشابه در برنامه می گردد. چرا که یک زیر برنامه یکبار تعریف شده و می تواند بارها صدا زده شود.
  4. وضوح برنامه بیشتر می شود.

در زبان c و ++c فقط یک نوع زیر برنامه به نام تابع وجود دارد.

نحوه تعریف و فراخوانی تابع:

تعریف و فراخوانی تابع از ۳ قسمت تشکیل شده:

  1. معرفی یا الگوی تابع
  2. فراخوانی یا صدا زدن تابع
  3. تعریف تابع

معرفی یا الگوی تابع:

بالای تابع main تایع های دیگر معرفی می شوند. معرفی برای نشان دادن ورودی ها و خروجی های تابع است.

int aver( int a, char b);

در معرفی تابع بالا که اسم آن aver است دارای ۲ ورودی که یکی int و دیگری char و همچنین خروجی تابع نوع int است. تابع می تواند هم بدون ورودی و هم بدون خروجی باشد که در اینصورت از void استفاده می کنیم.

void delay ( int a);

فراخوانی یا صدا زدن تابع:

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

x=aver(100,y);

delay (20000);

 

 تعریف تابع:

در تعریف تابع عملیات درون تابع نوشته می شود. در صورت نوشتن تعریف تابع در بالای تابع main دیگر نیازی به نوشتن معرفی تابع نیست اما معمولا تعریف تابع بعد از تابع main است.

int aver( int a, char b)

{

int p;

p=2*(a+b);

return p;

}

 هنگام تعریف تابع به متغیرهایی که داخل پرانتز نوشته می شوند پارامتر تابع و هنگام فرا خوانی تابع به متغیرهایی که داخل پرانتز نوشته می شوند آرگومان می گویند. هر کامپایلر استانداردی حداقل تا ۲۵۶ آرگومان را می تواند برای تابع قبول کند.

باید توجه کرد فضای پارامتر های تابع با آرگومان های تابع فرق دارد حتی اگر هم نام باشد. تعداد و نوع پارامتر با تعداد و نوع آرگومان متناظرشان یکسان باشد.

همانطور که می دانید متغیرهای درون یک تابع تعریف می شوند فقط درون آن تابع شناخته شده می باشند و به آنها متغیرهای محلی یا local گفته می شود. متغیرهای محلی فقط درون همان تابع شناخته شده می باشند. درون تابع های مختلف می توان متغیرهای همنام داشت ولی آنها ربطی به هم ندارند و در دو جای مختلف حافظه قرار دارند.

توجه کنید هنگام تعریف و معرفی نمی توان از type متغیرها فاکتور گرفت. مثلا دستور زیر غلط است:

int aver ( int a,b);

می توان از مقدار خروجی تابع استفاده نکرد هر چند که این عمل اغلب بی معناست ولی خطا نمی باشد. عبارت جلوی return می تواند داخل پرانتز باشد یا نباشد.

هنگام معرفی الگوی تابع نوشتن نام پارامترها اختیاری است و فقط نوع آنها کافی است. اگر خروجی تابع را در معرفی معلوم نکنیم نوع void در نظر گرفته خواهد شد.

روش های ارسال پارامترها به تابع:

به طور کلی به دو روش می توان پارامترها را به تابع ارسال کرد یا به عبارتی به دو روش می توان توابع را صدا زد:

  1. روش فراخوانی با مقدار (call by value)
  2. روش فراخوانی با ارجاع (call by reference)
روش فراخوانی با مقدار (call by value):
 
در این روش کپی آرگمان ها به پارامترها فرستاده می شود. بنابراین اگر درون تابع پارامترها تغیر کنند این تغیر به آرگمان های متناظرشان ( در تابع صدا زننده) اعمال نمی گردد. مانند تمام مثال های بالا.
 
روش فراخوانی با ارجاع (call by reference):
 
در این روش به جای آن که کپی آرگومان ها فرستاده شود آدرس آنها به کمک پوینترها ( pointers ) به تابع فرستاده شده و بدین ترتیب تغیراتی که به پارامترهای تابع صدا زده شده اعمال می گردد به آرگومان های متناظر در تابع صدا زننده نیز اثر می کند.
void aver ( int *pa, int *pb);
توجه فرستادن آرایه ها به تابع فقط از روش فراخوانی با ارجاع است. 

       

 

آموزش AVR GCC قسمت دوم

دستورات کنترلی

 

دستور if-else

فرم کلی این دستور به صورت زیر است:

if (شرط )   command1 ;

else command2  ;

اگر شرط جلوی if درست باشد دستور یک اجرا می شود . در غیر این صورت دستور جلوی else اجرا می شود ، وجود else در شرط if  اختیاری است. نوشتن پرانتز دور شرط الزامی است.

در قسمت شرط if می توان تابع را صدا زد به شرطی که خروجی تابع نوع void  نباشد.

اگر در صورت درست یا غلط بودن شرط بخواهیم چند دستور را اجرا کنیم می بایستی از {} استفاده کنیم.

مثال :

if ( x>y && y>0) {

       t=x;

      x=y;

      y=t;

}

else{

    x=1;

    y=2;

}

if تو در تو:

 در زبان ها می توان if های تو در تو نوشت ( if داخل if ) که نکته مهم در این نوع تشخیص هر else برای کدام if است. ( هر else به نزدیکترین if همان بلوک که قبلا آن if  به else دیگری مربوط نشده باشد، ارتباط دارد )

مثال:

if (a== 10) {

   if (b>6) {

       y=10;

       z=10*y;

   }

   else {

       y=0;

       z=1;

    }

    b=0;

}

else{

  z=0;

  y++;

}

if نردبانی :

یکی از روش ها برای بررسی چندین شرط با دستورات جداگانه، if نردبانی است. ( ساختار آن if بعد از else قبلی است )

مثال:

if (e1)

         s1;

else    if (e2)

         s2;

else    if (e3)

        s3;

          .

          .

          .

else  sn;

شرط e از بالا به پایین به ترتیب آزمایش می شود به محض آنکه یکی از شرط ها درست باشد جمله مربوط به آن اجرا شده و بقیه دستورات نردبان در نظر گرفته نمی شود و کنترل به خط بعد از نردبان منتقل می شود، اگر هیچکدام از شرط ها درست نباشد آخرین else اجرا می شود، در واقع  آخرین else مشابه شرایط پیش فرض است.

if نردبانی را در بعضی از مواقع می توان با دستور switch ساده تر نوشت.

دستور switch:

 فرم کلی این دستور:

switch ( expression ) {

      case constant 1:

                         statement sequnce

                         break;

      case constant 2:

                         statement sequnce

                         break;

                      .

                      .

                      .

           default:

                     statement sequnce

}

عبارتی که جلوی switch نوشته می شود با حالات مختلفی که جلوی case می آیند فقط از نظر تساوی مقایسه می شوند، هنگامی که یک حالت مساوی پیدا شود دستورات مربوط به آن case اجرا می شوند تا هنگامی که به دستور  break یا انتهای switch برسد. اگر هیچ حالت تساوی پیدا نشود دستورات default اجرا می شود ، default هم اختیاری است.

عبارت یا متغیر جلوی switch فقط می تواند صحیح یا کارکتری باشد همچنین می توان عبارت منطقی ، مقایسه ای ، محاسباتی و یا توابع با خروجی صحیح نوشت.

دستور default می تواند در هر جای از switch قرار گیرد که معمولا در انتهای switch قرار می گیرد.

اگر دو case یکسان در یک switch نوشته شود کامپایلر خطا می دهد. اگر دستورات جلوی case بیشتر از یک دستور باشد علامت {} نمی خواهد. جلوی case می توان چند حالت را با کاما از هم جدا کرد. جلوی case فقط مقادیر ثابت عددی یا کارکتری باید نوشته شود.

برای بررسی حالت های کوچکتر یا بزرگتر از if نردبانی استفاده می شود. درابتدای بلوک switch می توان متغیر تعریف کرد ولی در ابتدای case نمی توان تعریف کرد.

 حلقه while:

فرم کلی این دستور :

while ( شرط )

{

     دستورات

}

ابتدا شرط جلوی while بررسی می شود اگر شرط درست باشد دستورات حلقه اجرا شده و دوباره کنترل به اول حلقه منتقل می گردد. در این حالت دوباره شرط آزمایش می شود و دوباره عملیات دوباره تکرار می شود. اگر دستورات شامل یک دستور باشد نیازی به {} نیست. در صورتی که شرط جلوی while درست نباشد حتی یکبار حلقه اجرا نخواهد شد.

در شرط جلوی while می توان هر عبارت منطقی مجاز نوشت مثلا while (a+b>3*d)3

برای ایجاد حلقه دائم از while (1)1 استفاده می شود.

حلقه do-while:

فرم کلی:

do{

       دستورات

} while ( شرط);

 در اینجا بر عکس حلقه while ابتدا دستورات اجرا می شوند سپس شرط بررسی می شود پس حداقل حلقه یکبار اجرا می شود. در صورتی که دستورات یک دستور باشد نیازی به {} نیست.

 حلقه for:

برای تکرار تعدادی دستور به تعداد معین از حلقه for است.

فرم کلی :

for ( تغیر اندیس حلقه ; شرط ادامه حلقه ; مقدار دهی اولیه) {

         دستورات

}

اگر for شامل یک دستور باشد نیازی به {} نیست.

مثال :

int i,n=0;

for ( i=0;i<=9;i++)

n++;

ابتدا i صفر می شود ( این دستور فقط یکبار و قبل از ورود به حلقه انجام می شود) سپس i با عدد ۹ مقایسه می شود اگر شرط درست باشد دستورات حلقه اجرا می شود در غیر این صورت کنترل به بعد از حلقه می رود.

معمولا برای تکرار عملی به تعداد n بار از حلقه for (i=0;i1 استفاده می شود.اندیس حلقه می تواند به هر تعداد دلخواه کم یا زیاد شود     for (k=0;k!75;k-=5)1.

باید توجه داشت که بررسی درستی شرط همواره در اول حلقه انجام می شود لذا ممکن است دستورات حلقه اصلا اجرا نخواهد شد.

 هریک از سه جمله داخل پرانتز for را می توان ننوشت ولی همواره باید دو عدد سمی کالن (;) درون for باشد

for (;i<=9;) 1 .( در نتیجه دستور  for ( ; ; )1 یک حلقه دائم است ). همچنین هر یک از سه بخش می تواند شامل هر عبارت معتبر باشد حتی می تواند توابع مختلف داخلی یا تعریف شده توسط کاربر را صدا زد.

عملگر کاما را می توان در پرانتز جلوی for استفاده کرد بدین ترتیب انعطاف پذیری for بیشتر شده و مثلا می توان با دو یا چند متغیر کنترل حلقه را در دست داشت  for (x=0, y=1 ; 2*(x+y);x++,++y) 1 .

حلقه for  می تواند هیچ بدنه ای نداشته باشد که برای ایجاد تاخیر استفاده می شود.

اندیس حلقه می تواند صحیح یا کارکتری یا حتی اعشاری باشد.

حلقه تو در تو:

وقتی حلقه تکراری درون حلقه دیگری قرار داشته باشد به این حالت حلقه تو در تو گفته می شود. در این مورد به ازای هر بار اجرای حلقه خارجی ، حلقه داخلی به طور کامل انجام می شود. همچنین انتهای حلقه داخلی زودتر از حلقه خارجی است.

for (i=0 ; i<10 ; i++)

      for (j=0;j<5;j++)

     n++;

m++;

دستورات break و continue:

این دستورات داخل حلقه استفاده می شوند . هنگامی که به دستور break برسیم کنترل از حلقه داخل آن خارج می شود و به اولین دستور بعد از حلقه منتقل خواهد شد. اگر چند حلقه تو در تو داشته باشیم دستور break تنها باعث خروج از داخلی ترین حلقه می شود.

هر زمان که به دستور continue برسیم کنترل به خط اول حلقه می بریم و تمام مراحل حلقه تکرار می شود بجز مقدار دهی اولیه.

دستور goto:

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

معمولا دستور goto برای خروج از چندین حلقه تو در تو به کار می رود چون در این حالت از دستور break نمی توان استفاده کرد.

با این دستور نمی توان از زیربرنامه ای به زیربرنامه دیگر پرید.