چرا گیت یه متغیر با اسم عجیب false_but_the_compiler_does_not_know_it داره
خلاصهٔ کاملتر
نویسنده (آبهیناو اوپادهیای) میگه وقتی داشته تو سورس گیت میگشته، یه پوشه به اسم compiler-tricks چشمش رو گرفته و توش یه فایل پیدا کرده که فقط یه متغیر سراسری با اسم عجیب false_but_the_compiler_does_not_know_it_ داره که مقدارش صفره. این اسم یعنی «نادرسته، ولی کامپایلر نمیدونه». سؤال نویسنده اینه که چرا گیت همچین چیزی لازم داره.
این متغیر تو یه ماکرو به اسم NOT_CONSTANT استفاده میشه که عبارت ورودی رو با این متغیر OR منطقی میکنه:
#define NOT_CONSTANT(expr) ((expr) || false_but_the_compiler_does_not_know_it_)از اونجا که این متغیر صفره و گیت هیچوقت تغییرش نمیده، از نظر منطقی نتیجهٔ این عبارت دقیقاً برابر با خود expr هست. پس چرا اینطوری نوشتنش؟
ترفند اینجاست: این متغیر const تعریف نشده، پیوند خارجی (external linkage) داره، و تو یه واحد ترجمهٔ (translation unit) جدا از کدی که ازش استفاده میکنه تعریف شده. به همین خاطر موقع کامپایل فایلی که NOT_CONSTANT رو به کار میبره، کامپایلر نمیتونه ثابت کنه مقدارش همیشه صفر میمونه؛ از دید کامپایلر، یکی دیگه ممکنه عوضش کنه. عملاً همیشه صفره، ولی واضحاً صفر نیست.
اما این به چه دردی میخوره؟ نویسنده یه کاربردش رو تو refs/files-backend.c نشون میده. گیت تابعی به اسم create_ref_symlink داره که بسته به تنظیمات build، یا یه تابع واقعیه یا با ماکرو به یه ثابت (-1) تبدیل میشه. وقتی NO_SYMLINK_HEAD تعریف شده باشه، شرط !create_ref_symlink(...) عملاً میشه !(-1) که تو C برابر با false هست. کامپایلر اینجا یه if (0) میبینه و Clang هشدار میده که دستور continue دستنیافتنیه. ولی این فقط برای این یه پیکربندیه؛ رو پلتفرمهای دیگه اون شاخه واقعاً قابلاجراست.
گیت میخواد همون ساختار کنترل جریان رو تو همهٔ پیکربندیها نگه داره، برای همین شرط رو با NOT_CONSTANT میپیچه. حالا کامپایلر در زمان اجرا هنوز نتیجه رو false میبینه، ولی در زمان کامپایل نمیتونه ثابتش کنه، پس دیگه هشدار نمیده. به گفتهٔ نویسنده این ماکرو سال ۲۰۲۵ توسط یونیو همانو (نگهدارندهٔ گیت) اضافه شد؛ انگیزهٔ اولیهش هم کد مربوط به sigfillset() تو run-command.c بود که POSIX میگه میتونه شکست بخوره، ولی هدر بعضی پلتفرمها به کامپایلر میگفتن همیشه موفقه. به جای خاموش کردن کامل هشدار -Wunreachable-code، گیت ترجیح داد روشن نگهش داره و یه راه فرار کوچیک برای موارد مثبت کاذب بسازه.
نویسنده چند راهحل جایگزین رو هم بررسی میکنه: استفاده از #ifndef که منطق build رو وسط جریان کد پخش میکنه؛ خاموش کردن محلی هشدار با #pragma که خاص یه کامپایلره و شلوغه؛ یا استفاده از volatile که معنای خیلی قویتری داره و برای این کار زیادیه. به نظر نویسنده ترفند گیت دقیقتره چون فقط یه متغیر خارجی معمولی تو یه واحد ترجمهٔ جداست. در آخر هم با یه آزمایش کوچیک نشون میده که کامپایل و لینک معمولی این شاخه رو تو باینری نهایی نگه میداره، ولی با روشن کردن بهینهسازی زمان لینک (LTO) کامپایلر هر دو طرف رو با هم میبینه، میفهمه شرط همیشه false هست و شاخه رو حذف میکنه؛ یعنی بهترین حالت ممکن: هم هشدار اشتباه حذف میشه، هم در صورت فعال بودن LTO کد بیفایده از باینری پاک میشه.
نکات کلیدی:
- متغیر const نیست و تو یه فایل جدا تعریف شده، پس کامپایلر نمیتونه ثابت کنه همیشه صفره
- ماکروی NOT_CONSTANT جلوی هشدار مثبت کاذب -Wunreachable-code کلنگ رو میگیره
- مشکل از اونجا میاد که یه عبارت تو یه پیکربندی build ثابت میشه ولی تو بقیه نه
- این ماکرو رو یونیو همانو سال ۲۰۲۵ برای کد sigfillset اضافه کرد
- با LTO کامپایلر همه چیز رو با هم میبینه و شاخهٔ بیفایده رو از باینری حذف میکنه




