زبان برنامه نویسی سی/تبدیل و جایگزینی داده‌ها: تفاوت میان نسخه‌ها

محتوای حذف‌شده محتوای افزوده‌شده
بدون خلاصۀ ویرایش
بدون خلاصۀ ویرایش
خط ۲۱۰:
</code>
{{پایان چپ‌چین}}
 
در مثال بالا funcl یک تابع از نوع صحیح بلند اشاره‌گر است که دو پارامتر دارد : یکی تابع صحیح اشاره‌گری با نام ifn که پارامتری ندارد و دیگری تابع پوچ اشاره‌گری با نام vfn که آن هم پارامتری ندارد
 
==چگونگی تبدیل داده‌ها==
سطر ۲۴۱ ⟵ ۲۴۳:
==typedef==
 
کلیدواژه '''typedef''' برای تعیین یک یا چند شناسه برای نمایندگیجایگزینی ، جهت اعلان و تعریف یک نوع داده که خود می‌تواند از کلیدواژه‌هایی تشکیل شده باشد استفاده می‌شود . ضمن اینکه شما می‌توانید هر چند بار که خواستید برای یک یا چند نوع داده ، جایگزین یا جایگزین‌هایی تعریف کنید. مثلاً شما می‌توانید به جای اعلان و یا تعریف یک نوع داده صحیح ، به جای کلیدواژه int ، یک شناسهاسم رامثل بهinteger اسماز integerروی int بسازید و از آن جهت اعلان و تعریف داده‌های صحیح استفاده کنید . دقت کنید که با این کار کلیدواژه int منسوخ نمی‌شود ( یعنی همچنان می‌توانید در برنامه از کلیدواژه int برای اعلان و تعریف داده‌های عددی صحیح خود استفاده کنید ) . شکل کلی ایجاد جایگزین‌ها برای انوع داده توسط typedef به شکل زیر است :
 
<code>'''typedef''' ''data-type'' ''new-name''</code>
 
از typedef یا برایجهت خواناتر شدن کدهای نوشته شده استفاده می‌شود که این خواناتر شدن در دو محور معنی می‌یابد : ۱− کوتاه‌تر نوشته می‌شود ۲− به کدهای نوشته شده معنای قابل درکی می‌بخشد یا اینکه برای قابل حمل بودن و راحت‌تر شدن ویرایش برنامه استفاده می‌شود ؛ مثلاً فرض کنید نوعی داده ایجاد کرده‌اید که کوچککوچک‌تر یا بزرگبزرگ‌تر از مقداری که به آن نسبت داده شده است و در هر صورت نامتناسب با مقداری که می‌گیرد یا قرار است در کامپیوتر و سیستم عامل دیگری بگیرد است ، در چنین شرایطی برنامه‌نویس دیگر که قرار است کد شما را اصلاح کند با مشکلی بزرگ مواجه می‌شود و محبور است یک به یک تمام داده‌ها را عوض کند ، اما اگر از typedef استفاده کنید با یک تغییر در نوع داده مشکل حل می‌شود
 
مثال :
سطر ۲۸۳ ⟵ ۲۸۵:
{{پایان چپ‌چین}}
 
در مثال بالا دو جایگزین برای تعریف unsigned char تعیین نموده ایم و با کمک یکی از آنها یعنی little_number کاراکتر بدون علامت i را تعریف کرده و با کمک دیگری یعنی pixel_vlaue متغیر کاراکتری بدون علامت red را تعریف نموده و سپس هر دو را در خروجی رابط خط‌دستوری چاپ کرده‌ایم
 
'''دقت کنید :''' ۱ − در سیستم‌هایی که مبتنی بر استاندارد پازیکس POSIX نوشته می‌شوند که شامل همه سیستم عامل‌های مبتنی بر یونیکس یا شبه‌یونیکس‌ها می‌شود پسوند t_ در کتابخانه‌ها برای بسیاری از پردازش‌ها ، داده‌ها و تابع‌ها از پیش تعریف شده است ؛ بنابراین مؤکداً توصیه می‌کنیم که اگر می‌خواهید شناسه جایگزینی بسازید ،( درست مثل شناسه‌های دیگر که پیش‌تر نیز گفتیم ) از اسامی‌ای که t_ را در نام خود دارند ، استفاده نکنید و از آنها پرهیز کنید ، چرا که بسیاری از خطاها در برنامه‌نویسی در سیستم‌های سازگار با پازیکس به همین خاطر رخ می‌دهند ۲ − typedef و شناسه‌هایی که ایجاد کرده‌اید مشمول قانون حوزه دید در زبان C می‌شوند ( بنابراین شناسه‌ای که با typedef داخل یک بلوک تعریف شده ، داخل بلوکی دیگر قابل استفاده نیست و از دید آن بلوک پنهان می‌ماند )
 
مثال :
سطر ۳۱۲ ⟵ ۳۱۴:
{{پایان چپ‌چین}}
 
در مثال بالا شناسه uchar در تابع mian مقدار a را دارد و در تابع foo مقدار z را . ابتدا یک شناسه جایگزین با نام uchar برای یک نوع داده کاراکتری بدون علامت تعریف کردیم که سراسری است . سپس داخل تابع main مقدار و موجودی a را در داخل کاراکتر بدون علامت ch که با کمک شناسه جایگزین uchar تعریف شده است قرار دادیم و سپس در بلوک تابع foo بار دیگر کاراکتر بدون علامت ch را تعریف نمودیم ( باز هم با استفاده از شناسه جایگزین uchar ) که مقدار و موجودی z را داخل آن قرار دادیم . در هر دو تابع مقدار ch را با کمک تابع کتابخانه‌ای printf در خروجی خطرابط دستوریخط‌دستوری چاپ نموده‌ایم
 
ما در زبان C مجاز هستیم تا اشاره‌گرها را نیز با کمک typedef تعریف و جایگزین نمائیم مثلاً typedef int* iptr شناسه iptr را به عنوان اعلان کننده اشاره‌گری از نوع صحیح تعریف می‌کند . بنابراین با الگوی نوشته شده اگر در داخل برنامه خود بنویسیم : iptr *a شناسه a اشاره‌گر به اشاره‌گری از نوع صحیح خواهد بود و iptr b[10] شناسه b را به عنوان آرایه ۱۰ عنصری از اشاره‌گر از نوع صحیح تعریف می‌کند
 
از کلیدواژه typedef می‌توان برای تعریف ساختمان‌ها و اجتماع‌ها هم استفاده کرد . برای این کار هم می‌توانید با استفاده از typedef و نوشتن کلیدواژه struct یا union و با استفاده از نام برچسب ساختمان یا اجتماع ( به ترتیب ) و سپس با نام جایگزینجایگزینِ شناسه جدیدی برای تعریف، نمونه استفادهایجاد کنید و هم می‌توانید هنگام تعریف ساختمان یا اجتماع ، پیش از کلیدواژه struct یا union کلیدواژه typedef را بنویسید سپس برچسب ساختمان یا اجتماع را نوشته و سپس بعد از بلوک و پیش از سمی‌کالن ( نقطه ویرگول ) ِ ساختمان یا اجتماع نام یا نام‌های جایگزین را بنویسید و سپس با نام جایگزین نمونه یا نمونه‌هایی ایجاد کنید
 
مثال :
سطر ۴۰۱ ⟵ ۴۰۳:
{{پایان چپ‌چین}}
 
'''نکته :''' در مثال بالا می‌توان به جای اینکه تابع function را با typedef اشاره‌گر تعریف کرد ، آن را یک تابع غیراشاره‌گر تعریف نموده و سپس در تابع call_function پارامتر p را اشاره‌گر تعریف نمود تا تابع function را به عنوان آرگومان بپذیرد
 
'''دقت کنید :''' در جایگزینی تابع به واسطه typedef نامی که برای تابع انتخاب می‌کنید ، همان نام جایگزین برای تابع است
 
'''توضیح :''' در مثال بالا یک تابع با نام add تعریف نمودیم که دو پارامتر a و b را می‌پذیرد و آنها را با هم جمع می‌کند و حاصل‌جمع را به عنوان خروجی عرضه می‌کند . تابع sub دو پارامتر a و b را می‌گیرد و b را از a کم می‌کند و نتیجه را عرضه می‌کند . تابعی از نوع صحیح اشاره‌گر با نام function که با همین نام جایگزین نیز شده است ( به خاطر وجود کلیدواژه typedef ) با دو پارامتر a و b اعلان شده و سپس تابع call_function با پارامتر اول که یک function است که خود یک صحیح اشاره‌گر می‌باشد تعریف شده و همچنین دو پارامتر دیگر یعنی a و b را می‌پذیرد کهو به عنوان خروجی تابعی را از نوع صحیح اشاره‌گر که روی دو پارامتر a و b پردازش می‌کند به عنوان خروجی عرضه می‌کند . در نهایت در تابع main یک متغیر صحیح با نام sum به عنوان حاصل اعلان شده که بار اول call_function را احضار می‌کند و مقدار آن را ذخیره می‌کند که به عنوان آرگومان ، تابع add و اعداد ۱۰ و ۵ را به ترتیب به آن پاس می‌دهدداده‌ایم و سپس عدد حاصل را در خروجی رابط خط‌دستوری پرینت می‌کند . در بار دوم متغیر sum برابر با خروجی احضار تابع call_function با آرگومان‌های تابع sub و اعداد ۱۰ و ۵ ( به ترتیب ) است و این مقدار در خروجی رابط خط‌دستوری با کمک تابع printf چاپ می‌شود
 
می‌توان تابع‌های اشاره‌گری که تابع‌های اشاره‌گری نیز دارند را هم با کمک typedef خواناتر نمود . مثلاً در کرنل FreeBSD نوشته شده بود :
 
{{چپ‌چین}}
<code>code>void (*signal(int sig, void (*func)(int)))(int);</code>
{{پایان چپ‌چین}}
 
سطر ۴۱۷ ⟵ ۴۱۹:
{{چپ‌چین}}
<code>typedef void (*SignalHandler)(int signum);
<br>
</code>extern SignalHandler signal(int signum, SignalHandler handler);
{{پایان چپ‌چین}}
 
که بسیار خواناتر است . SignalHandler نام تابع و نام جایگزین تابع پوچ اشاره‌گر است که یک پارامتر از نوع صحیح دارد و به کمک آن تابع signal را تعریف نموده‌ایم تا تابعی از نوع پوچ اشاره‌گر باشد که یک پارامتر صحیح دارد و یک پارامتر دیگر با نام handler که تابعی از نوع پوچ اشاره‌گر است که یک پارامتر صحیح نیز دارد
 
به مثال زیر دقت کنید :
سطر ۴۵۲ ⟵ ۴۵۵:
{{پایان چپ‌چین}}
 
که بسیار خلاصه‌تر و خواناتر است . هر دو قطعه کد یک کار را انجام می‌دهند اما کد دوم خلاصه‌تر و خواناتر است . در توضیح قطعه کد دوم :
ابتدا با کمک typedef یک ساختمان را که سه عضو صحیح دارد با نام جایگزین DIM3 ایجاد کردیم . در خط پایانی fnptr از نوع DIM3FN است که در خط قبل‌تر توسط typedef به صورت یکعنوان تابع با نام DIM3FN و با نام جایگزین همسان ( یعنی DIM3FN ) تعریف شده بود که از نوع ساختمان اشاره‌گر است و یک پارامتر DIM3 که یک ساختمان اشاره‌گر است و یک پارامتر دیگر که صحیح است تعریف نموده و در هنگام احضار می‌پذیرد ( چون هنوز به بحث تابع نرسیده‌ایم بیش از این مثال‌های پیچیده نمی‌زنیم و توضیحات ما در سطحی که مثال می‌زنیم برای آشنایی با تابع و توضیح در مورد بحثی که در آن هستیم می‌باشند )
 
'''نکته :''' با کمک اشاره‌گرها و ساختمان‌ها و البته با استفاده از typedef نوعی داده می‌توان ایجاد کرد که به آن داده نامرئی می‌گویند و دسترسی به اعضای آن امکان‌پذیر نیست مگر با استفاده از تابع‌های دسترس . پس از به اتمام رسیدن بحث‌های زبان C به بیان ترفندهایی که در زبان C به کار می‌روند می‌پردازیم
 
'''تفاوت typedef و دستور مستقیم define'''
 
typedef ، تنها شناسه‌ای را که برای آن معین نموده‌ایم با نوع داده تعریف شده جایگزین می‌کند در حالی که دستور مستقیم define هر چیزی را حتی مقدار و موجودیموجودی‌ای را که با define تعریف کرده باشیم جایگزین می‌کند . define می‌تواند حتی کلیدواژه‌ها و یا تابع‌های کتابخانه‌ای را هم جایگزین کند ( که البته کاری ریسک‌پذیر است و باید از آن اجتناب شود ) typedef مشمول قانون حوزه دید می‌شود اما دستور مستقیم define# حوزه‌ای ندارد و هر جا که تعریفی برای آن مقرر شده باشد پس از دستور ، هر تعریف شده را ، با مقدارش جایگزین می‌کند که البته یکی از تفاوت‌های عمده آنtypedef و define این است که define نمی‌تواند نوع داده‌ای را نمی‌تواند تعریف کند و فقط هر جا که کاراکتر یا رشته تعریف شده رابرای ببیندخود در سر راهش قرار بگیرد با مقداری که برای آن تعریف شده جایگزین می‌کند مثلاً typedef با کد typedef float * fp هر fp را به اشاره‌گر اعشاری تبدیل می‌کند و اگر بنویسیم : fp a, b, c معادل خواهد بود با : float *a, *b, *c در حالی که اگر از دستور مستقیم define استفاده کنیم و بنویسیم :
 
{{چپ‌چین}}
سطر ۴۶۵ ⟵ ۴۶۸:
{{پایان چپ‌چین}}
 
و سپس در یک خط کد fp a, b, c را بنویسیم ، معادل خواهد بود با : float *a, b, c که فقط متغیر اولی ، یعنی a را به عنوان متغیر اعشاری اشاره‌گر تعریف می‌کند و نه b و c را و این دو متغیر اعشاری غیر اشاره‌گر اعلان می‌شوند
 
[[رده:زبان برنامه نویسی سی]]