1. هیچ عبارت اجرایی را در دستور switch قبل از برچسب case اول قرار ندهید، زیرا این عبارت ها هیچ گاه اجرا نشده و توسط کامپایلر نادیده گرفته می شوند. در صورتی که برنامه نویس متغیرها را قبل از case تعریف و مقداردهی اولیه کند و سپس در صدد استفاده از آنها درون هر یک از عبارت های case باشد، آن متغیرها درون حوزه switch شناخته شده هستند ولی در واقع مقداردهی اولیه نشده و حاوی مقادیر نامشخصی (Garbage) می باشند.
نادرست |
درست |
int func(int expr) { switch(expr){ int i = 4; f(i); case 0: i = 17; /* falls through into default code */ default: printf(â%d\nâ, i); } return 0; } |
int func(int expr) { int i = 4; /* Move the code outside the switch block */ f(i); /* Now the statements will get executed */
switch(expr) { case 0: i = 17; /*falls through into default code */ default: printf(â%d\nâ, i); } return 0; } |
2. هر مجموعه دستوراتی را که با case شروع میشود با دستور break تمام کنید.
نادرست |
درست |
enum WidgetEnum { WE_W, WE_X, WE_Y, WE_Z } widget_type; widget_type = WE_X;
switch (widget_type) { case WE_W: /* ... */ case WE_X: /* ... */ break; case WE_Y: case WE_Z: /* ... */ break; default: /* Can't happen */ /* Handle error condition */ }
|
enum WidgetEnum { WE_W, WE_X, WE_Y, WE_Z } widget_type; widget_type = WE_X;
switch (widget_type) { case WE_W: /* ... */ break; case WE_X: /* ... */ break; case WE_Y: case WE_Z: /* ... */ break; default: /* Can't happen */ /* Handle error condition */ } |
3. پیش از مقدار دهی اولیه از متغیرها استفاده نکنید.
4. از حافظه ()malloc شده نباید پیش از مقداردهی اولیه شدن استفاده کنید، زیرا محتویات آن نامشخص است!
5. در صورتی که یک عدد صحیح با یک عدد صحیح با اندازه بزرگتر مقایسه شود و یا به متغیر عدد صحیح با اندازه بزرگتر نسبت داده شود، باید به صورت صریح با استفاده از دستورات تبدیل انواع (Casting) در اندازه بزرگتر مورد ارزیابی قرار گیرد.
6. از طول اشاره گر برای تعیین کردن طول نوعی که به آن اشاره می کند، استفاده نکنید. دقت کنید که گرفتن طول «اشاره گر به یک نوع خاص»، همواره طول اشاره گر را بر می گرداند و نه طول نوعی را که به آن اشاره می کند. این مسئله در زمان محاسبه طول آرایه ها بسیار مشکل ساز می شود. برای مثال کد زیر به اشتباه از طول اشاره گر به جای طول نوعی را که اشارهگر به آن اشاره میکند، استفاده می کند:
نادرست |
درست |
double *allocate_array(size_t num_elems) { double *d_array;
if (num_elems > SIZE_MAX/sizeof(d_array)) { /* Handle error condition */ } d_array = (double *)malloc(sizeof(d_array) * num_elems); if (d_array == NULL) { /* Handle error condition */ } return d_array; } |
double *allocate_array(size_t num_elems) { double *d_array;
if (num_elems > SIZE_MAX/sizeof(*d_array)) { /* Handle error condition */ } d_array = (double *)malloc(sizeof(*d_array) * num_elems); if (d_array == NULL) { /* Handle error condition */ } return d_array; } |
7. به اشارهگرهای تهی (Null Pointer) ارجاع مجدد ندهید. تلاش برای ارجاع مجدد به اشاره گرهای تهی منجر به رفتارهای تعریف نشده ای (Undefined Behavior) همچون خروج غیر منتظره از برنامه (Abnormal Program Termination) می شود. برای مثال در کد برنامه زیر input_str در یک متغیر رشته ای به نام str که به صورت پویا مقداردهی شده است، کپی می شود. در صورتی که تابع ()malloc به درستی اجرا نشود (fail)، یک اشاره گر تهی یا null را برگردانده و به str اختصاص می دهد. زمانی که به str در ()memcpy ارجاع مجدد می شود، برنامه به شکل غیر منتظره ای رفتار می کند.
نادرست |
درست |
#include <string.h> #include <stdlib.h>
void f(const char *input_str) { size_t size = strlen(input_str) + 1; char *c_str = (char *)malloc(size); memcpy(c_str, input_str, size); /* ... */ free(c_str); c_str = NULL; /* ... */ }
|
#include <string.h> #include <stdlib.h>
void f(const char *input_str) { size_t size; char *c_str;
if (NULL == input_str) { /* Handle error */ }
size = strlen(input_str) + 1; c_str = (char *)malloc(size); if (NULL == c_str) { /* Handle error */ } memcpy(c_str, input_str, size); /* ... */ free(c_str); c_str = NULL; /* ... */ } |
8. بسیاری از توابع (I/O Functions و Memory Allocation Functions) یک مقدار معتبر را بر میگردانند یا مقداری را بر میگردانند که نشاندهنده بروز خطا است، برای مثال می توان به -1 یا اشاره گر تهی (Null Pointer) اشاره کرد. فرض را بر این گذاشتن که توابع همواره اجرای موفقی خواهند داشت یکی از اشتباهات خطرناکی است که منجر به بروز رفتار تعریف نشده و یا خارج از انتظار می شود. بنابراین ضروری است که برنامه ها خطاهای احتمالی را تشخیص داده و به صورت مناسب آنها را با توجه به سیاست رسیدگی به خطاها (Error-Handling Policy) مدیریت کنند.