همکاری با C
سلام بدون هیچ کد واسط یا ابزار سازندهی پوشش، مستقیم با کتابخانههای C کار میکند. یعنی کتابخانهی استاندارد C و هر کتابخانهی دیگری که به C نوشته شده از برنامهی سلام در دسترس است.
درونداد
در بلوک درونداد: تابعهای C را با گونهی ورودیها و خروجیشان اعلان کنید و بعد مثل هر تابع سلام صدایشان بزنید. این اعلانها بدنه ندارند: کد در کتابخانهی C است و سلام فقط باید بداند چطور صدایش بزند. نام تابعهای C همان نام انگلیسی خودشان میماند.
درونداد:
تابع sqrt(x: اعشار۶۴): اعشار۶۴
تابع abs(x: صحیح): صحیح
پایان
تابع ریشه:
سرچاپ sqrt(۲.۰)
سرچاپ abs(-۴۲)
پایانمترجم به این اعلانها کاملاً اعتماد میکند. اگر اعلان با تابع واقعی C نخواند، مثلاً صحیح بنویسید جایی که C عدد double میخواهد، هیچ هشداری نمیبینید و برنامه دادهی بیمعنا میخواند. پس امضای هر تابع را با دقت از سرآیند کتابخانه یا راهنمای آن بردارید.
گونههای همارز C
| C | سلام |
|---|---|
int، unsigned int | صحیح (صحیح۳۲)، طبیعی (طبیعی۳۲) |
long long، int64_t، uint8_t | صحیح۶۴، صحیح۶۴، طبیعی۸ |
size_t | اندازه مثبت |
ssize_t، intptr_t | اندازه |
double، float | اعشار۶۴، اعشار۳۲ |
const char* که متن نگه میدارد | رشته |
char* یا unsigned char* که بایت نگه میدارد | طبیعی۸* یا تهی* |
void*، T* | تهی*، T* |
| اشارهگر تابع | تهی* یا درونداد تابع (...) R |
رشتهی سلام از قبل به بایت صفر ختم میشود، پس میشود آن را مستقیم به هر تابع C که رشته میخواهد داد.
printf و تابعهای با ورودی متغیر
تابع C که شمار ورودیهایش ثابت نیست، مثل printf، با ... پس از ورودیهای ثابتش اعلان میشود. قاعدههای قالب C برقرارند: %d برای صحیح، %f برای اعشار۶۴، %s برای رشته، و پهناهایی مثل %-8s و %6.2f برای ستونبندی:
درونداد:
تابع printf(format: رشته، ...): صحیح
تابع strlen(s: رشته): اندازه مثبت
تابع atoi(s: رشته): صحیح
تابع toupper(c: صحیح): صحیح
پایان
تابع ریشه:
سرچاپ "رسید"
printf("%-8s %3d x %6.2f\n"، "coffee"، ۲، ۳.۵)
printf("%-8s %3d x %6.2f\n"، "bagel"، ۱، ۲.۲۵)
شمار := atoi("12") + atoi("30")
سرچاپ "اقلام:"، شمار
واژه := "salam"
سرچاپ "بایتها:"، strlen(واژه)
سرچاپ "حرف اول:"، نویسهازکد(toupper(کدنویسه(واژه)))
پایانخروجی printf و سرچاپ به همان ترتیبی میآید که برنامه نوشته است، چون سلام پیش از صدا زدن تابع C که چیزی مینویسد، بافر خروجی خودش را خالی میکند. فاصلهگذاری %-8s بایتها را میشمارد نه حرفها را، و هر حرف فارسی دو بایت است؛ برای همین در این نمونه نام کالاها لاتین است. برای ستونبندی متن فارسی از سرچاپ یا بستهی قالب بندی استفاده کنید.
اشارهگر، بافر و بایت صفر
بسیاری از تابعهای C در حافظهای که به آنها میدهید مینویسند. این حافظه را با بستهی حافظه بگیرید، اشارهگرش را بدهید و وقتی کارتان تمام شد آزادش کنید؛ یک دیرکن درست پس از گرفتن حافظه نمیگذارد فراموش شود. اشارهگر را مثل آرایه شماره بزنید: بافر[ای] یک خانه را میخواند یا مینویسد.
واردسازی حافظه
درونداد:
تابع snprintf(buf: تهی*، size: اندازه مثبت، format: رشته، ...): صحیح
تابع getenv(name: رشته): رشته
پایان
تابع ریشه:
بافر := حافظه.تخصیص صفرشده(۳۲ برگردان طبیعی۶۴) برگردان طبیعی۸*
دیرکن حافظه.آزادسازی(بافر برگردان تهی*)
ن := snprintf(بافر برگردان تهی*، ۳۲ برگردان اندازه مثبت، "%s-%05d"، "INV"، ۴۲)
برچسب := بافر برگردان رشته
سرچاپ ن، برچسب
بایتها := [۷۲، ۱۰۵، ۰، ۳۳، ۳۳]
تکرار ۵ در ای:
بافر[ای] = بایتها[ای] برگردان طبیعی۸
پایان
متن := بافر برگردان رشته
سرچاپ "بهصورت رشته:"، طول(متن)، "بایت"
ناپایا جمع := ۰
تکرار ۵ در ای:
جمع += بافر[ای] برگردان صحیح
پایان
سرچاپ "از راه اشارهگر:"، جمع
مقدار := getenv("SALAM_EXAMPLE_UNSET")
اگر (مقدار برگردان تهی*) == پوچ:
سرچاپ "SALAM_EXAMPLE_UNSET تعریف نشده است"
پایان
پایانبه خط وسط خروجی دقت کنید. رشته در نخستین بایت صفر تمام میشود، پس پنج بایت H i 0 ! ! به رشتهی دوبایتی Hi تبدیل میشوند و هیچ خطایی هم دیده نمیشود؛ باقی بایتها بیصدا از دست میروند. متنی که از C میآید را میشود رشته کرد، اما دادهی دودویی مثل تصویر، پروندهی فشرده یا بستهی شبکه را نه. دادهی دودویی را به شکل اشارهگر و طول نگه دارید و از راه اشارهگر بخوانید، همان کاری که حلقهی جمع هر پنج بایت میکند.
تابع C که ممکن است رشتهای برنگرداند، مثل getenv برای متغیری که تعریف نشده، اشارهگر تهی برمیگرداند. پیش از استفاده آن را با (مقدار برگردان تهی*) == پوچ بسنجید. رشتهای که C برمیگرداند مال کتابخانهی C است؛ هرگز خودتان آزادش نکنید.
پیوند کتابخانه
تابعهای کتابخانهی استاندارد C چیز دیگری لازم ندارند. برای هر کتابخانهی دیگر، با پیوند پیش از بلوک درونداد به پیونددهنده بگویید کدام را بردارد. نوع پیوند همیشه نوشته میشود:
پیوند پویا "sqlite3"کتابخانهی اشتراکی را پیوند میدهد، مثل-lsqlite3در ساخت Cپیوند ایستا "z"کتابخانهی ایستایlibz.aرا میخواهد که درون برنامه کپی میشودپیوند چارچوب "Cocoa"یک چارچوب مک را پیوند میدهد
پیوند "m" بدون نوع خطاست و پیامش هر سه نوع را نام میبرد. چارچوب فقط روی مک وجود دارد، پس آن را درون یک اگر زمان ترجمه بگذارید، مثل این نمونه که کتابخانهی ریاضی C را پیوند میدهد:
پیوند پویا "m"
اگر سلام سیستم مک:
پیوند چارچوب "CoreFoundation"
پایان
درونداد:
تابع fmod(x: اعشار۶۴، y: اعشار۶۴): اعشار۶۴
تابع hypot(x: اعشار۶۴، y: اعشار۶۴): اعشار۶۴
تابع round(x: اعشار۶۴): اعشار۶۴
پایان
تابع ریشه:
سرچاپ "باقیماندهی ۱۷ دقیقه در بازههای ۵ دقیقهای:"، fmod(۱۷.۰، ۵.۰)
سرچاپ "قطر صفحهی ۳ در ۴:"، hypot(۳.۰، ۴.۰)
سرچاپ "گرد شدهی ۲.۵:"، round(۲.۵)
پایانبرونداد: تابعهای سلام برای C
بعضی تابعهای C شما را صدا میزنند. qsort آرایهای از هر گونهای را مرتب میکند و برای مقایسهی دو خانه از تابعی که شما میدهید کمک میگیرد. تابع سلامی که C باید صدایش بزند در بلوک برونداد: میآید؛ آن وقت یک تابع واقعی C با همان نام ساده است و &نام نشانی آن است که جایی که C اشارهگر تابع میخواهد داده میشود:
واردسازی حافظه
درونداد:
تابع qsort(base: تهی*، count: اندازه مثبت، width: اندازه مثبت، compare: تهی*)
پایان
برونداد:
تابع by_score(الف: تهی*، ب: تهی*): صحیح:
ایکس := (الف برگردان صحیح۳۲*)[۰]
ایگرگ := (ب برگردان صحیح۳۲*)[۰]
اگر ایکس < ایگرگ:
برگشت -۱
وگرنه ایکس > ایگرگ:
برگشت ۱
پایان
برگشت ۰
پایان
پایان
تابع ریشه:
نمرهها := [۴۲، ۷، ۱۹، ۸۸، ۳]
ن := طول(نمرهها)
پ := حافظه.تخصیص((ن * ۴) برگردان طبیعی۶۴) برگردان صحیح۳۲*
دیرکن حافظه.آزادسازی(پ برگردان تهی*)
تکرار ن در ای:
پ[ای] = نمرهها[ای]
پایان
qsort(پ برگردان تهی*، ن برگردان اندازه مثبت، ۴ برگردان اندازه مثبت، &by_score)
ناپایا سطر := ""
تکرار ن در ای:
سطر += " " + پ[ای]
پایان
سرچاپ "مرتبشده:" + سطر
پایانتابع مقایسه دو اشارهگر تهی* به دو خانه میگیرد، آنها را به صحیح۳۲* برمیگرداند و با [۰] میخواند. عددها باید در حافظهای باشند که C به آن دسترسی دارد، برای همین برنامه آنها را در بافری از بستهی حافظه کپی میکند، میگذارد qsort همانجا مرتبشان کند و نتیجه را از راه اشارهگر میخواند.
تابع برونداد همیشه یک نماد عمومی و معمولی C است و این قاعدهها را دارد:
- هر تابع بلوک باید بدنه داشته باشد؛ اعلان بیبدنه جایش در
درونداداست - متغیر، تابع عام و ورودی
...مجاز نیست همگانی،درخطونادرخطمجاز نیست؛ فقطبیکاره،نابونابرگشت- نام باید یککلمهای باشد، چون همان نام C میشود. با حروف لاتین بنویسیدش: پشتیبان LLVM مترجم هنوز نمیتواند نام برونداد غیرلاتین بسازد
صدا زدن از راه اشارهگر تابع C
جهت دیگر هم کار میکند. (&نام) برگردان درونداد تابع (اعشار۶۴) اعشار۶۴ نشانی یک تابع C، یا یک تابع برونداد سلام، را به مقداری گونهدار تبدیل میکند که میشود نگهش داشت، جابهجایش کرد و صدایش زد. درونداد تابع (...) R گونهی ورودی هم هست، پس یک تابع سلام میتواند با هر تابع C به همان شکل کار کند:
درونداد:
تابع sqrt(x: اعشار۶۴): اعشار۶۴
تابع cbrt(x: اعشار۶۴): اعشار۶۴
پایان
برونداد:
تابع halve(x: اعشار۶۴): اعشار۶۴:
برگشت x / ۲.۰
پایان
پایان
تابع نمایش(نام: رشته، ر: درونداد تابع (اعشار۶۴) اعشار۶۴، ع: اعشار۶۴):
سرچاپ نام + "(" + ع + ") ="، ر(ع)
پایان
تابع ریشه:
نمایش("sqrt"، (&sqrt) برگردان درونداد تابع (اعشار۶۴) اعشار۶۴، ۶۴.۰)
نمایش("cbrt"، (&cbrt) برگردان درونداد تابع (اعشار۶۴) اعشار۶۴، ۶۴.۰)
نمایش("halve"، (&halve) برگردان درونداد تابع (اعشار۶۴) اعشار۶۴، ۶۴.۰)
پایاننام یک تابع معمولی سلام وقتی بهعنوان مقدار به کار رود، نشانی آن به شکل صحیح۶۴ است، همان چیزی که جدولهای فراخوان مثل مسیریاب وب میگیرند. برای جای تهی* یا برای تبدیل به تابع C گونهدار، &نام بنویسید.
در ویندوز ۳۲ بیتی، تابعهای Win32 با قرارداد فراخوانی stdcall کار میکنند. اشارهگر به چنین تابعی، مثلاً نشانیای که GetProcAddress برمیگرداند، گونهی درونداد فراخوان استاندارد تابع (...) R میگیرد تا فراخوانی با آن جور باشد. روی هر هدف دیگری این واژه چیزی را تغییر نمیدهد.
چند قاعدهی سرانگشتی
- امضای هر تابع C را دقیق بنویسید؛ مترجم نمیتواند آن را بسنجد.
- برای متن از
رشتهو برای بایت از اشارهگر و طول استفاده کنید. - هر چه با بستهی حافظه میگیرید آزاد کنید، و چیزی را که C برمیگرداند آزاد نکنید مگر راهنمایش بگوید.
- اشارهگری را که C ممکن است تهی برگرداند پیش از استفاده بسنجید.
- وقتی کتابخانهی استاندارد سلام کاری را انجام میدهد همان را به کار ببرید: صدا زدن C را برایتان انجام میدهد و روی همهی سیستمها یکسان کار میکند.
گاهی هر سیستم تابع C متفاوتی لازم دارد. بلوک درونداد را میشود درون یک اگر سلام سیستم ویندوز: سطح بالا گذاشت؛ درس ترجمهی شرطی را ببینید.