موضوع مقاله: سی (زبان برنامه‌نویسی) | مخاطب: عمومی | لحن: دانشنامه‌ای | ساختار: عنوان، مقدمه، 3 بخش، جمع‌بندی | مقاله: | # سی (زبان برنامه‌نویسی) | مقدمه: سی یک زبان برنامه‌نویسی از نوع همه‌منظوره، کامپایل‌شونده، سطح میانی، ساخت‌یافته، دستوری و روندگرا می‌باشد که در سال ۱۹۷۲ توسط دنیس ریچی در آزمایشگاه‌های بل ساخته شد. | ## بخش 1: سی (زبان برنامه‌نویسی) | در سال ۱۹۶۷ مارتین ریچاردز زبان BCPL را برای نوشتن نرم‌افزارهای سیستم‌عامل و کامپایلر در دانشگاه کمبریج ابداع کرد. سپس در سال ۱۹۷۰ کن تامسون زبان B را بر مبنای ویژگی‌های زبان BCPL نوشت و از آن برای ایجاد اولین نسخه‌های سیستم‌عامل یونیکس در آزمایشگاه‌های بل استفاده کرد. زبان C در سال ۱۹۷۲ توسط دنیس ریچی از روی زبان B و BCPL در آزمایشگاه بل ساخته‌شد و ویژگی‌های جدیدی همچون نظارت بر نوع داده‌ها نیز به آن اضافه شد. ریچی از این زبان برای ایجاد سیستم‌عامل یونیکس استفاده کرد اما بعدها اکثر سیستم‌عامل‌های دیگر نیز با همین زبان نوشته‌شدند. استفادهٔ گسترده این زبان در انواع رایانه‌ها و سخت‌افزارهای مختلف باعث شد که نسخه‌های مختلفی از این زبان به‌وجود آید که با یکدیگر ناسازگار بودند. در سال ۱۹۸۳ مؤسسه استانداردهای ملی آمریکا (ANSI) کمیته‌ای موسوم به X3J11 را را مأمور کرد تا یک تعریف فاقد ابهام و مستقل از ماشین را از این زبان تدوین نماید. بررسی اجمالی مانند بسیاری از زبان‌های رویه‌ای در سنت الگول، سی دارای امکاناتی برای برنامه‌نویسی ساخت یافته است و دامنهٔ متغیر واژگان را امکان‌پذیر می‌سازد. در C، کلیهٔ کدهای اجرایی در زیر برنامه‌ها (که «توابع» نیز نامیده می‌شوند) وجود دارد (گرچه به معنای برنامه‌نویسی کاربردی کاملاً دقیق نیست). متن منبع برنامهٔ C با فرمت آزاد است و با استفاده از دکتر کلمات به عنوان یک اصطلاح کننده بیان و بندهای فرفیژه برای گروه‌بندی جمله‌ها استفاده می‌شود. در حالی که C ویژگی‌های خاصی را که در زبان‌های دیگر یافت می‌شود (مانند جهت‌یابی اشیاء و جمع‌آوری زباله)، این موارد را می‌توان پیاده‌سازی یا تقلید کرد، غالباً با استفاده از کتابخانه‌های خارجی (به عنوان مثال، سیستم اشیاء GLib یا جمع‌آوری زباله Boehm). این زبان‌ها بسیاری از ساختارهای کنترلی خود و سایر ویژگی‌های اصلی را از C ترسیم کرده‌اند. بیشتر آن‌ها (پایتون یک استثناء چشمگیر) نیز نحو کاملاً مشابهی را با C نشان می‌دهند، و آن‌ها تمایل دارند ترکیب و نحو قابل تشخیص C را با نوع زیرین ترکیب کنند. سیستم‌ها، مدل‌های داده‌ها و معنایی که می‌توانند تفاوت چشمگیری با یکدیگر داشته باشند. تاریخچه تحولات اولیه منشأ C با توسعه سیستم عامل یونیکس کاملاً مرتبط است، که در ابتدا با زبان اسمبلی بر روی PDP-7 توسط دنیس ریچی و کن تامپسون پیاده‌سازی شده و چندین ایده از همکاران را دربر گرفته است. تامپسون یک زبان برنامه‌نویسی را برای ایجاد برنامه‌های کاربردی برای سیستم عامل جدید می‌خواست. در عوض، او یک نسخه برش خورده از زبان برنامه‌نویسی سیستم‌های BCPL که اخیراً توسعه یافته بود، ایجاد کرد. توضیحات رسمی BCPL در آن زمان موجود نبود و تامپسون نحو (syntax) را اصلاح و کم‌حرف‌تر و B را مشابه اما کمی ساده‌تر تولید می‌کند با این حال، کمترین ابزارها نهایتاً در B نوشته شدند زیرا خیلی کند بود و B نمی‌توانست از ویژگی‌های PDP-11 مانند آدرس پذیری بایت بهره ببرد. کامپایلر C و برخی از برنامه‌های کاربردی ساخته شده با آن در نسخه ۲ یونیکس گنجانده شده است. در نسخه ۴ یونیکس، که در نوامبر ۱۹۷۳ منتشر شد، هسته یونیکس به‌طور گسترده‌ای در C دوباره اجرا شد. K&R C در سال ۱۹۷۸، برایان کرنیگان و دنیس ریچی چاپ اول کتاب زبان برنامه‌نویسی C را منتشر کردند. این کتاب که به عنوان K&R برای برنامه نویسان C شناخته شده بود، سالها به عنوان مشخصات غیررسمی زبان مورد استفاده قرار گرفت. در سال ۱۹۸۳، مؤسسه استاندارد ملی آمریکا (ANSI) کمیته ای با نام X3J11 تشکیل داد تا مشخصات استاندارد C را ایجاد کند. X3J11 براساس استاندارد C بر روی اجرای یونیکس؛ با این حال، بخش غیرقابل حمل از کتابخانه یونیکس C به گروه کاری IEEE 1003 واگذار شد تا پایه ای برای استاندارد POSIX 1988 باشد. در سال ۱۹۹۰، استاندارد ANSI C (با تغییرات قالب بندی) توسط سازمان بین‌المللی استانداردسازی (ISO) به عنوان ISO / IEC 9899: 1990 تصویب شد، که گاهی C90 نیز نامیده می‌شود؛ بنابراین، اصطلاحات "C89" و "C90" به همان زبان برنامه‌نویسی اشاره دارند. C99 استاندارد C در اواخر دهه ۱۹۹۰ بازنگری شد و منجر به انتشار ISO / IEC 9899: 1999 در ۱۹۹۹ شد، که معمولاً به آن "C99" گفته می‌شود. C99 چندین ویژگی جدید از جمله توابع درون خطی، چندین نوع داده جدید (از جمله int long long و یک نوع مختلط برای نشان دادن اعداد مختلط)، آرایه‌های با طول متغیر و اعضای آرایه انعطاف‌پذیر، پشتیبانی بهبود یافته از IEEE 754 نقطه شناور، پشتیبانی از ماکرو متغیر را معرفی کرد؛ و پشتیبانی از نظرات تک خطی که با // شروع می‌شود، مانند BCPL یا C ++. C11 در سال ۲۰۰۷، کار بر روی تجدید نظر در مورد استاندارد C، به‌طور غیررسمی به نام "C1X" تا انتشار رسمی آن در تاریخ ۲۰۱۱-۱۲-۰۸ آغاز شد. | ## بخش 2: سی (زبان برنامه‌نویسی) | کمیته استاندارد C دستورالعمل‌هایی را برای محدود کردن استفاده از ویژگی‌های جدید که توسط آزمایش‌های موجود آزمایش نشده‌اند، اتخاذ کرده است. استاندارد C11 چندین ویژگی جدید به C اضافه می‌کند و کتابخانه، از جمله ماکرو نوع عمومی، ساختارهای ناشناس، پشتیبانی بهبود یافته یونیکد، عملیات اتمی، چند رشته‌ای و عملکردهای محدود شده را بررسی می‌کند. همچنین برخی از بخش‌های موجود در کتابخانه C99 را به اختیاری تبدیل کرده و سازگاری با ++C را بهبود می‌بخشد. C18 C18 که گاهی C17 هم نامیده می‌شود در سال ۲۰۱۷ توسعه و در ژوئن سال ۲۰۱۸ منتشر شده استاندارد فعلی زبان برنامه‌نویسی C است. این معرفی هیچ ویژگی جدید زبان نداشت، فقط اصلاحات فنی و شفاف‌سازی در مورد نقص C11 را ارائه می‌دهد. علاوه بر فراهم آوردن امکان نوشتن کدهای برنامهٔ کوتاه‌تر، غنی‌تر و کاراتر، گاهی مواردی پیش می‌آید که انجام محاسبات مورد نیاز برنامه تنها توسط اشاره گرها امکان‌پذیر می‌باشد. اگر چه در ظاهر کار با اشاره‌گرها مشکل است و درک برنامه‌ای که از آنها استفاده شده است ساده نیست، اما در حقیقت اگر از آنها به درستی استفاده گردد، وضوح و سادگی برنامه افزایش می‌یابد. روش مستقیم دسترسی به حافظه برای ذخیره‌سازی مقداری در آن، یا بازیابی محتوای ذخیره شده، استفاده از نام متغیر است. همین که متغیری معرفی شد، سیستم بر اساس نوع اعلام شده، تعداد بایت لازم را به آن اختصاص می‌دهد و آدرس متغیر، شماره اولین بایت از مجموعهٔ اختصاص یافته است. پس از آن به راحتی از طریق نام متغیر به محل موردنظر دسترسی یافته، محتوای آن پردازش می‌گردد. اما گاهی لازم می‌شود به جای نام، آدرس متغیر در اختیار برنامه‌نویس قرار گیرد تا از طریق آن دستیابی به محل مربوط صورت گیرد. در زبان C، به راحتی می‌توان آدرس یک متغیر را در اختیار داشت و مقدارش را در حافظه ذخیره نمود تا در زمان نیاز، توسط آن به صورت غیرمستقیم به محل موردنظر دست یافت. آرایه‌ها بسیاری از موارد پیش می‌آید که برنامه‌نویس نیاز به استفاده از تعداد زیادی متغیر پیدا می‌کند؛ مثلاً اگر بخواهیم جملات ۱ تا ۱۰۰ سری فیبوناچی را برای استفاده ذخیره کنیم، به صد متغیر نیاز داریم. تعریف این صد متغیر به صورت مستقل و با نام‌های جداگانه کاری سخت و طاقت‌فرساست و البته معقول نیست. به همین خاطر در زبان C قابلیتی پیش‌بینی شده تا بتواند تعداد دلخواهی متغیر از یک نوع را به راحتی ایجاد کرد. به این متغیرها که در حافظه پشت سر هم قرار می‌گیرند و همگی از یک نوع هستند آرایه (Array) می‌گویند. همان‌طور که در ریاضی برای مشخص کردن یک جمله از دنباله از اندیس استفاده می‌کنیم، در C نیز برای مشخص کردن یک متغیر خاص از اندیس استفاده می‌شود. همان‌طور که مشاهده می‌کنید خانهٔ پنجم شمارهٔ ۴ دارد و این بدین خاطر است که خانه‌ها از شمارهٔ ۰ تا n-1 (که n تعداد خانه‌هاست) شماره‌گذاری می‌شود. اندازهٔ هر خانه به اندازهٔ نوع تعریف شده است؛ مثلاً در مثال قبل اگر int دو بایت اشغال کند آرایهٔ array، در کل ۲۰ بایت از حافظه اشغال خواهد کرد. این که خانه‌ها پشت سر هم قرار می‌گیرند ویژگی کارایی است که در بحث اشاره‌گرها به کار می‌آید. مدیریت حافظه یکی از مهم‌ترین کارکردهای یک زبان برنامه‌نویسی، فراهم آوردن امکاناتی برای مدیریت حافظه و مواردی است که در حافظه ذخیره می‌شوند. C سه روش مشخص برای اختصاص حافظه برای اشیاء ارائه می‌دهد: تخصیص حافظه استاتیک: فضایی برای جسم در زمان کامپایل در دودویی فراهم می‌شود. این اشیاء تا حدودی (یا طول عمر) دارند تا زمانی که باینری که شامل آنها است در حافظه بارگذاری شود. تخصیص خودکار حافظه: اشیاء موقتی را می‌توان در پشته ذخیره کرد و پس از خارج شدن از بلوکی که در آن اعلام شده است، این فضای به‌طور خودکار آزاد و قابل استفاده مجدد می‌شود. تخصیص حافظه پویا: بلوک‌های حافظه با اندازه دلخواه را می‌توان در زمان اجرا با استفاده از توابع کتابخانه مانند malloc از منطقه ای از حافظه به نام پشته درخواست کرد. این بلوک‌ها تا زمانی که با استفاده مجدد از عملکرد مجدد کتابخانه یا مجدداً آزاد شوند، برای استفاده مجدد آزاد می‌شوند تخصیص حافظه خودکار: اشیا موقتی می‌توانند بر روی پشته ذخیره شوند، این فضای اختصاص داده شده به اشیا به صورت اتوماتیک پس از خارج شدن از بلاکی که اشیا در آنها تعریف شده‌اند، آزاد و دوباره قابل استفاده خواهد بود. تخصیص حافظه پویا: اندازه‌های اختیاری از بلاک‌های حافظه می‌توانند توسط توابع کتابخانه‌ای همانند تابع malloc از ناحیه‌ای از رم موسوم به هیپ در هنگام اجرای برنامه درخواست بشود. | ## بخش 3: سی (زبان برنامه‌نویسی) | این بلاک‌های حافظه تا زمانی‌که توسط تابع free به سیستم بازگردانده نشوند در حافظه باقی می‌مانند. برای تخصیص حافظه به صورت پویا (دینامیک) باید آدرس بلوک حافظه‌ای که توسط تابع malloc گرفته می‌شود را در یک اشاره گر ذخیره کنیم. به عنوان مثال، تخصیص حافظه استاتیک اختصاص کمی به سربار دارد، تخصیص خودکار ممکن است کمی بیشتر از سربار باشد و تخصیص حافظه پویا به‌طور بالقوه می‌تواند مقدار زیادی از سربار را برای تخصیص و جابجایی داشته باشد. ماهیت پایدار اشیاء استاتیک برای حفظ اطلاعات حالت در طول فراخوانی‌های عملکردی مفید است، تخصیص خودکار به راحتی قابل استفاده است اما فضای پشته معمولاً بسیار محدودتر و گذرا از حافظه استاتیک یا فضای پشته است و تخصیص حافظه پویا امکان تخصیص مناسب اشیاء را می‌دهد که اندازه فقط در زمان اجرا شناخته شده است. در صورت امکان، تخصیص اتوماتیک یا استاتیک معمولاً ساده‌ترین است زیرا ذخیره‌سازی توسط کامپایلر اداره می‌شود، و برنامه‌نویس را از روی خطای بالقوه خطا در اختصاص و آزاد سازی فضای ذخیره‌سازی آزاد می‌کند. با این وجود بسیاری از ساختارهای داده می‌توانند در زمان اجرا تغییر کنند و از آنجا که تخصیص استاتیک (و تخصیص خودکار قبل از C99) باید در زمان کامپایل اندازه ثابت داشته باشد، موقعیت‌های بسیاری وجود دارد که تخصیص پویا لازم است. (به عنوان مثال از آرایه‌های اختصاص داده شده پویا به مقاله در مورد malloc مراجعه کنید) برخلاف تخصیص خودکار، که می‌تواند در زمان اجرا با عواقب کنترل نشده از کار بیفتد، عملکردهای تخصیص پویا هنگام ذخیره‌سازی مورد نیاز، نشانه (به صورت مقدار اشاره گر تهی) را برمی‌گردانند. نمی‌توان اختصاص داد (قبل از اینکه برنامه حتی بتواند اجرای آن را شروع کند، معمولاً توسط لینک دهنده یا لودر تشخیص داده می‌شود) مگر در مواردی که مشخص شده باشد، اشیاء استاتیک حاوی مقادیر نشانگر صفر یا تهی هنگام شروع برنامه هستند. اشیاء اختصاص داده شده به صورت خودکار و پویا فقط درصورتی تنظیم می‌شوند که مقدار اولیه صریحاً مشخص شود. در غیر این صورت آنها در ابتدا مقادیر مشخص نشده‌ای دارند (به‌طور معمول، هر الگوی بیتی که در آن ذخیره می‌شود، حتی ممکن است یک مقدار معتبر برای آن نوع نداشته باشد). بسیاری از کامپایلرهای مدرن سعی در کشف و هشدار دربارهٔ این مشکل دارند، اما هم مثبت‌های کاذب و هم منفی کاذب می‌تواند رخ دهد. مسئله دیگر این است که تخصیص حافظه پشته باید با کاربرد واقعی آن در هر برنامه همگام سازی شود تا در استفاده مجدد از آن تا حد امکان استفاده شود. به عنوان مثال، اگر تنها اشاره گر برای تخصیص حافظه پنهان از محدوده خارج شود یا مقدار آن را قبل از بازنویسی بازنویسی کرده باشد فراخوانی شود، پس از آن حافظه برای استفاده مجدد بعدی قابل بازیابی نیست و در اصل برای برنامه از بین می‌رود، پدیده ای معروف به a نشت حافظه در مقابل، امکان آزادسازی حافظه وجود دارد اما همچنان به آن مراجعه می‌شود و منجر به نتایج غیرقابل پیش‌بینی می‌شود. به‌طور معمول، علائم در بخشی از برنامه به دور از خطای واقعی ظاهر می‌شوند، و پیگیری مشکل را دشوار می‌کند. (چنین مواردی در زبانهایی که جمع‌آوری زباله‌های اتوماتیک دارند بهبود یافته است) توابع کتابخانه‌ای C دارای توابعی است که از قبل نوشته شده‌اند، و توابع کتابخانه‌ای نامیده می‌شوند. در واقع فرایندهایی که پر کاربرد هستند و در اغلب برنامه‌ها مورد استفاده قرار می‌گیرند به صورت توابع مستقل قبلاً نوشته شده‌اند؛ که به آنها هدر نیز می‌گویند. هر کتابخانه به‌طور معمول دارای یک فایل هدر است، که شامل نمونه‌های اولیه توابع موجود در کتابخانه است که ممکن است توسط یک برنامه مورد استفاده قرار گیرد، و اظهارات انواع داده‌های خاص و نمادهای کلان مورد استفاده با این توابع. برای اینکه یک برنامه از کتابخانه استفاده کند، باید پرونده سرصفحه کتابخانه را شامل شود، و کتابخانه باید با برنامه در ارتباط باشد، که در بسیاری موارد به پرچم‌های کامپایلر احتیاج دارد. رایج‌ترین کتابخانه C، کتابخانه استاندارد C است که توسط استانداردهای ISO و ANSI C مشخص شده است و همراه با اجرای هر C (اجرای‌هایی که محیط‌های محدود مانند سیستم‌های جاسازی شده را هدف قرار می‌دهند، تنها می‌تواند زیر مجموعه ای از کتابخانه استاندارد را ارائه دهد). این کتابخانه از ورودی و خروجی جریان، تخصیص حافظه، ریاضیات، رشته‌های کاراکتر و مقادیر زمانی پشتیبانی می‌کند. چندین هدر استاندارد جداگانه (به عنوان مثال stdio.h) رابط‌های این و سایر امکانات کتابخانه استاندارد را مشخص می‌کند. مجموعه رایج دیگری از توابع کتابخانه C مواردی است که توسط برنامه‌هایی که مخصوص سیستم‌های یونیکس و شبه یونیکس هستند، به ویژه توابعی که رابط کاربری هسته را هدف قرار می‌دهند مورد استفاده قرار می‌گیرد. از آنجا که بسیاری از برنامه‌ها به زبان C نوشته شده‌اند، انواع مختلفی از کتابخانه‌های دیگر در دسترس هستند. کتابخانه‌ها غالباً به زبان C نوشته می‌شوند، زیرا کامپایلرهای C کد شیئی کارآمد را تولید می‌کنند. برنامه نویسان سپس رابط‌هایی را برای کتابخانه ایجاد می‌کنند تا روال‌ها از زبان‌های سطح بالاتر مانند جاوا، پرل و پایتون استفاده شوند. زبانهای مرتبط در سال‌های بعد و با ظهور روش‌های برنامه‌نویسی شئ‌گرا نسخه جدیدی از زبان C بنام ++C توسط بی‌یارنه استراس‌تروپ در اوایل ۱۹۸۰ در آزمایشگاه‌های بل توسعه یافت. با گسترش شبکه و اینترنت، نیاز به زبانی احساس شد که برنامه‌های آن بتوانند بر روی هر ماشین و هر سیستم‌عامل دلخواهی اجرا گردد. | ## جمع‌بندی | شرکت سان مایکروسیستمز در سال ۱۹۹۵ میلادی زبان جاوا را برمبنای C و ++C ایجاد کرد که هم‌اکنون از آن در سطح وسیعی استفاده می‌شود و برنامه‌های نوشته شده به آن بر روی هر کامپیوتری که از جاوا پشتیبانی کند (تقریباً تمام سیستم‌های شناخته شده) قابل اجرا می‌باشد.