کلمات کلیدی: دستورات
assert
اجرا را با خطای زمان اجرا متوقف میکند اگر عبارت به طور منطقی نادرست ارزیابی شود. به نظر میرسد فقط در بلاک main() کار میکند. دستور assert باید برای نشان دادن خطای منطقی (برنامهنویس) استفاده شود، هرگز خطای زمان اجرا (کاربر).
main()
{
assert (MAX_PLAYERS == GetMaxPlayers()); // ascertain that the definition of MAX_PLAYERS is equal to the actual number of server slots in use
}
break
فوراً از حلقه خارج میشود، فقط حلقه سطح بالا را ترک میکند، نه همه حلقههای فعلی.
for (new i = 0; i < 10; i++)
{
printf("%d", i);
if (i == 5)
{
break;
}
}
تولید خواهد کرد:
0
1
2
3
4
5
در حالی که:
for (new i = 0; i < 10; i++)
{
if (i == 5)
{
break;
}
printf("%d", i);
}
تولید خواهد کرد:
0
1
2
3
4
چون حلقه فوراً خارج میشود هیچ حلقهای به 10 نمیرسد و دومی قبل از چاپ عدد 5 تمام میشود.
case
نتیجه خاصی در دستور switch مدیریت میکند. نتیجه میتواند یا عدد تکی، انتخابی از اعداد یا محدودهای از اعداد باشد:
new
switchVar = 10;
switch (switchVar)
{
case 1:
{
printf("switchVar is 1");
}
case 4:
{
printf("switchVar is 4");
}
case 2, 3, 5:
{
printf("switchVar is either 2, 3 or 5");
}
case 7 .. 11:
{
printf("switchVar is somewhere between 7 and 11 inclusive (7, 8, 9, 10 or 11)");
}
default:
{
printf("switchVar is not 1, 2, 3, 4, 5, 7, 8, 9, 10 or 11");
}
}
continue
شبیه break اما فقط به تکرار بعدی حلقه میرود. مهم است توجه کنید که نقطهای که به آن میپرد بسته به نوع حلقهای که استفاده میکنید متفاوت است.
for (new i = 0; i < 10; i++)
{
if (i == 5)
{
continue;
}
printf("%d", i);
}
تولید خواهد کرد:
0
1
2
3
4
6
7
8
9
یک continue بعد از print اساساً هیچ کاری نخواهد کرد. در حلقه for، continue به دستور سوم در دستور for میپرد (در این مثال قسمت "i++")، این متفاوت از نحوه رفتار آن در حلقه while است:
new
i = 0;
while (i < 10)
{
if (i == 5)
{
continue;
}
printf("%d", i);
i++;
}
این حلقه بینهایت تولید خواهد کرد چون continue بعد از "i++;" خواهد پرید و به قسمت "while (i < 10)" برخواهد گشت. در این زمان، "i" همچنان 5 خواهد بود چون "i++;" هرگز فراخوانی نشد، و بنابراین continue دوباره فراخوانی خواهد شد و "i" برای همیشه در 5 گیر خواهد کرد.
default
نتایج دستور switch که صراحتاً توسط دستورات case مدیریت نمیشوند را مدیریت میکند. برای مثال به مثال case مراجعه کنید.
do
do نوعی حلقه است که میتواند با while برای تولید حلقهای که همیشه حداقل یک بار اجرا خواهد شد استفاده شود. نقطه ویرگول بعد از while () در مثال زیر را توجه کنید:
new
i = 10;
do
{
printf("%d", i);
i++;
}
while (i < 10);
"i" واضح است که کمتر از 10 نیست اما این حلقه تولید خواهد کرد:
10
به هر حال. حلقه while مشابه:
new
i = 10;
while (i < 10)
{
printf("%d", i);
i++;
}
هیچ خروجی نخواهد داد چون شرط فوراً شکست میخورد.
اینها همچنین برای اجتناب از بررسیهای دوتایی مفید هستند:
new
checkVar = 10;
if (checkVar == 10)
{
new
i = 0;
while (checkVar == 10)
{
checkVar = someFunction(i);
i++;
}
}
این واضح نیست که مشکل عمدهای باشد اما شما checkVar را دو بار پشت سر هم در ابتدای حلقه بررسی میکنید، که کاملاً بیفایده است، اما if لازم است چون نیاز دارید اگر شرط درست باشد کدی انجام دهید اما خارج از حلقه (این وضعیت نسبتاً رایجی است). این میتواند با انجام این کار بهبود یابد:
new
checkVar = 10;
if (checkVar == 10)
{
new
i = 0;
do
{
checkVar = someFunction(i);
i++;
}
while (checkVar == 10);
}
در این مورد نتیجه دقیقاً همان خواهد بود اما مهم این است که یک بررسی بیفایده کمتر.
else
else وقتی دستور if شکست بخورد فراخوانی میشود (فرض کنیم موجود باشد):
new
checkVar = 5;
if (checkVar == 10)
{
printf("This will never be called");
}
else
{
printf("The if statement failed so this will be displayed");
}
else همچنین میتواند با if ترکیب شود:
new
checkVar = 2;
if (checkVar == 1)
{
printf("This will not be called"):
}
else if (checkVar == 2)
{
printf("The first if failed so the second was checked and is true");
}
else
{
printf("This will not be called as one of the ifs was true");
}
exit
این برنامه فعلی را فوراً خارج میکند.
main()
{
exit;
return 0;
}
for
حلقه for نوعی حلقه است که شامل سه مرحله، مقداردهی اولیه، مقایسه و بهروزرسانی. هر کدام با نقطه ویرگول جدا میشوند و هر کدام میتوانند با تنظیم فضای خالی حذف شوند. ابتداییترین حلقه for این است:
for ( ; ; ) {}
این هیچ مقداردهی اولیه، مقایسه و بهروزرسانی ندارد و در نتیجه تا ابد ادامه خواهد داشت (مقایسه، چون غایب است، به طور پیشفرض درست است).
یکی از رایجترین حلقهها این است:
for (new i = 0; i < MAX_PLAYERS; i++)
{
printf("%d", i);
}
مقداردهی اولیه در این حلقه:
new i = 0;
نقطه ویرگول پایان مقداردهی اولیه را نشان میدهد. این متغیر جدیدی به نام i اعلان میکند که فقط با این حلقه قابل استفاده است. بعد مقایسه انجام میشود. این i را با MAX_PLAYERS (پیشفرض 500 - #define را ببینید) مقایسه میکند و اگر کمتر باشد ادامه میدهد. سپس محتویات حلقه اجرا میشود. ابتدا "0" را چاپ خواهد کرد. در نهایت بهروزرسانی انجام میشود "i++"، این مقدار i را افزایش میدهد. حالا یک تکرار کامل انجام شده، حلقه، همانطور که از نامش پیداست، حلقه میزند و به مرحله مقایسه برمیگردد (مقداردهی اولیه فقط یک بار در هر فراخوانی انجام میشود).
نتیجه این حلقه چاپ همه اعداد از 0 تا 499 شامل است. حلقه while معادل (نادیده گرفتن تأثیرات continue) این خواهد بود:
new
i = 0;
while (i < MAX_PLAYERS)
{
printf("%d", i);
i++;
}
سه مرحله میتوانند در صورت لزوم بسیار پیچیدهتر شوند با استفاده از کاما برای بخشهای اول و آخر و مقایسههای استاندارد برای بخش میانی:
for (new i = 0, j = 200; i < MAX_PLAYERS && j > 10; i++, j -= 2)
{
printf("%d %d", i, j);
}
این دو متغیر جدید ایجاد خواهد کرد و آنها را به 0 و 200 تنظیم خواهد کرد، سپس در حالی که یکی کمتر از 200 و دیگری بیشتر از 10 است حلقه خواهد زد، یکی را هر بار افزایش خواهد داد و دیگری را هر بار 2 تا کاهش خواهد داد.
همانطور که قبلاً گفته شد scope متغیرها معمولاً به حلقه محدود است:
for (new i = 0; i < MAX_PLAYERS; i++)
{
printf("%d", i);
}
printf("%d", i);
این خطا خواهد داد چون "i" بعد از پایان حلقه وجود ندارد. اما:
new
i = 0;
for ( ; i < MAX_PLAYERS; i++)
{
printf("%d", i);
}
printf("%d", i);
مشکلی ندارد چون "i" در حلقه اعلان نشده. همچنین میتوانید "i" را در حلقه مقداردهی اولیه کنید اما در آنجا اعلان نکنید:
new
i;
for (i = 0; i < MAX_PLAYERS; i++)
{
printf("%d", i);
}
printf("%d", i);
goto
goto و برچسبها عموماً در جامعه کدنویسی دلسرد کننده هستند چون آنچه انجام میدهند معمولاً میتواند بهتر با بازسازی صحیح کد انجام شود. اما اساساً goto یک پرش است:
goto my_label;
printf("This will never be printed");
my_label:
printf("This will be printed");
اما کامپایلر goto را خیلی خوب مدیریت نمیکند پس آن اصلاً بهینه نخواهد شد و چیزهایی مثل:
{
new
i = 5;
if (i == 5)
{
goto my_label;
}
else
{
my_label:
return 0;
}
}
هشداری در مورد انواع return ناسازگار خواهد داد چون فکر میکند شاخه درست هیچی برنمیگرداند وقتی که در واقع برمیگرداند، فقط به روش بسیار پیچیده. همچنین:
MyFunction()
{
new
i = 5;
if (i == 5)
{
goto my_label;
}
return 0;
my_label:
return 1;
}
هشدار کد غیرقابل دسترس خواهد داد با وجود اینکه در واقع قابل دسترس است.
نحو اصلی:
label:
goto label;
برچسب باید در خطی مستقل باشد و با دونقطه تمام شود، نه نقطه ویرگول. برچسبها همان محدودیتهای نامگذاری متغیرها و توابع و غیره را دارند.
if
If یکی از مهمترین عملگرها است. تعیین میکند که آیا کاری انجام شود یا نه و بر اساس آن عمل میکند، همراه با goto، پایه تقریباً همه ساختارهای کنترل دیگر است:
for (new i = 0; i < 10; i++)
{
}
معادل است با:
new
i = 0;
for_loop:
if (i < 10)
{
i++;
goto for_loop;
}
شرایطی که if میتواند بگیرد برای این پست خیلی زیاد هستند اما برخی در زیر فهرست شدهاند:
عملگر توضیح مثال نتیجه وقتی a=1, b=0 نتیجه وقتی a=1, b=1 نتیجه وقتی a=0, b=1 نتیجه وقتی a=0, b=0 == بررسی میکند یک چیز برابر دیگری است if (a == b) false true false true != بررسی میکند یک چیز مثل دیگری نیست if (a != b) true false true false < بررسی میکند یک چیز کمتر از دیگری است if (a < b)
false false true false > بررسی میکند یک چیز بیشتر از دیگری است if (a > b) true false false false <=
بررسی میکند یک چیز کمتر یا مساوی دیگری است if (a <= b)
false true true true >= بررسی میکند یک چیز بیشتر یا مساوی دیگری است if (a >= b)
true true false true && بررسی میکند دو چیز درست هستند (نه 0) if (a && b) false true false false || بررسی میکند حداقل یکی از دو چیز درست است (نه 0) if (a || b) true true true false ! بررسی میکند چیزی نادرست است if (!(a == b)) true false true false
واضح است که با اینها میتوانید شرایط پیچیده بسازید:
if (a == b && (c != d || f < g))
این درست خواهد بود اگر a مثل b باشد و یا f کمتر از g باشد یا c مثل d نباشد (یا هر دو).
return
این از تابع خارج میشود و میتواند دادهای به تابع فراخواننده برگرداند:
MyFunction()
{
new
someVar = OtherFunction();
}
OtherFunction()
{
return 5;
}
someVar حالا 5 خواهد بود.
MyFunction()
{
if (SomeFunction())
{
printf("Returned 1");
}
}
SomeFunction()
{
return random(2);
}
این یا 1 یا 0 به دستور if تابع فراخواننده برخواهد گرداند. 1 درست و 0 نادرست است پس متن فقط اگر 1 برگردانده شود چاپ خواهد شد. اما:
MyFunction()
{
if (SomeFunction())
{
printf("Returned something between 1 and 10");
}
}
SomeFunction()
{
return random(11);
}
این 0، 1، 2، 3، 4، 5، 6، 7، 8، 9 یا 10 برخواهد گرداند. هر چیزی که 0 نباشد درست است پس متن اگر چیزی بین 1 و 10 برگردانده شود نمایش خواهد داد.
همچنین میتوانید return را با رشتهها استفاده کنید:
MyFunction()
{
printf("%s", SomeFunction());
}
SomeFunction()
{
new
str[10] = "Hello";
return str;
}
"Hello" (بدون گیومه) چاپ خواهد کرد.
همچنین مجبور نیستید چیزی برگردانید:
MyFunction()
{
SomeFunction();
}
SomeFunction()
{
return;
}
اما اگر این کار را کنید باید مطمئن شوید که return تابع هرگز استفاده نمیشود:
MyFunction()
{
if (SomeFunction())
{
printf("Problem");
}
}
SomeFunction()
{
return;
}
اینجا SomeFunction چیزی برنمیگرداند اما MyFunction بررسی میکند که آیا مقدار برگردانده شده از SomeFunction درست است یا نه - نه درست است نه نادرست چون اصلاً وجود ندارد، پس خطای کامپایل دریافت خواهید کرد. عدم return پیشفرض است، پس:
SomeFunction()
{
return;
}
و:
SomeFunction()
{
}
یکی هستند.
در نهایت، نمیتوانید مقدارهای return را مخلوط کنید:
MyFunction()
{
SomeFunction();
}
SomeFunction()
{
if (random(2))
{
return 1;
}
else
{
return;
}
}
این خطا خواهد داد چون نمیداند چه کار کند.
SomeFunction()
{
if (random(2))
{
return 1;
}
}
نیز مجاز نیست چون return پیشفرض هیچی است.
sleep
sleep تابع شبهای است که اجرا را برای تعداد داده شده میلیثانیه متوقف میکند:
printf("Time 0s");
sleep(1000);
printf("Time 1s");
این فقط در main() کار میکند، نه callback ها چون در thread PAWN اجرا میشود.
state
state بخشی از state machine و سیستم autonoma در PAWN است، این thread را برای اطلاعات بیشتر ببینید.
switch
switch اساساً سیستم ساختاریافته if/else if/else است:
switch (someVar)
{
case 1:
{
printf("one");
}
case 2:
{
printf("two");
}
case 3:
{
printf("three");
}
default:
{
printf("other");
}
}
فقط روش کمی کارآمدتر (و بسیار تمیزتر) انجام این کار است:
if (someVar == 1)
{
printf("one");
}
else if (someVar == 2)
{
printf("two");
}
else if (someVar == 3)
{
printf("three");
}
else
{
printf("other");
}
while
while نوع حلقهای شبیه for و do..while است. عمل اصلی دستور if است که اگر درست باشد کدی انجام میدهد و به if برمیگردد. اگر نادرست باشد به بعد از کد حلقه میرود - else ندارد. برگشت به مثال goto:
new
i = 0;
for_loop:
if (i < 10)
{
i++;
goto for_loop;
}
این همچنین میتواند نوشته شود:
new
i = 0;
while (i < 10)
{
i++;
}
do و for را برای اطلاعات بیشتر ببینید.