آرایه‌ها در مقابل اشاره‌گرها در سطح سخت‌افزار

در C، آرایه‌ها و اشاره‌گرها اغلب قابل‌تعویض به‌نظر می‌رسند، و بسیاری از برنامه‌نویسان با آن‌ها به‌عنوان یک چیز واحد رفتار می‌کنند. با این حال در سطح سخت‌افزار، آن‌ها به توالی‌های دستوری قابل‌توجهی متفاوت با ویژگی‌های کارایی متفاوت کامپایل می‌شوند. این مقاله این دو رویکرد را با استفاده از اسمبلی RISC-V مقایسه می‌کند تا دقیقاً نشان دهد چرا کد مبتنی بر اشاره‌گر اغلب سریع‌تر است.

آرایه در مقابل اشاره‌گرحساب اشاره‌گرمحاسبه آدرس RISC-V

~3 min read · Updated Sep 6, 2026

چرا این مقایسه اهمیت دارد

در کد سطح بالای C، پیمایش یک آرایه با استفاده از نمادگذاری ایندکس و پیمایش آن با استفاده از اشاره‌گر، هر دو طبیعی به‌نظر می‌رسند و اغلب نتیجه منطقی یکسانی تولید می‌کنند. اما یک کامپایلر هرکدام از این سبک‌ها را به الگوی متمایزی از دستورات RISC-V ترجمه می‌کند، و کار سخت‌افزاری حاصل یکسان نیست. درک این تفاوت منبع رایجی از بینش درباره اینکه چرا سبک‌های کدنویسی خاصی در عمل سریع‌تر اجرا می‌شوند است.

رویکرد ایندکس‌گذاری آرایه

یک حلقه ساده را در نظر بگیرید که هر عنصر یک آرایه را با استفاده از نمادگذاری ایندکس پاک می‌کند:

void clear1(long array[], long size) {
    for (long i = 0; i < size; i += 1) {
        array[i] = 0;
    }
}

برای ترجمه array[i] به یک دسترسی حافظه، پردازنده باید در هر تکرار حلقه، آدرس حافظه را با ضرب کردن ایندکس i در اندازه هر عنصر مجدداً محاسبه کند، سپس آن نتیجه را به آدرس پایه آرایه اضافه کند:

Loop:
bge i, size, Exit
slli t0, i, 3
add t1, array, t0
sd x0, 0(t1)
addi i, i, 1
jal x0, Loop
Exit:

توجه کنید به دستورات اضافی slli (شیفت به چپ، که اینجا برای ضرب در ۸ بایت استفاده شده) و add که در هر تکرار صرفاً برای محاسبه آدرس از روی ایندکس مورد نیازند.

رویکرد مبتنی بر اشاره‌گر

حالا همان منطق را با استفاده از حساب اشاره‌گر به‌جای ایندکس‌گذاری در نظر بگیرید:

void clear2(long *array, long size) {
    long *p;
    for (p = &array[0]; p < &array[size]; p = p + 1) {
        *p = 0;
    }
}

اینجا، کامپایلر می‌تواند حلقه‌ای تولید کند که در آن خود اشاره‌گر مستقیماً در هر تکرار به‌اندازه یک مقدار ثابت افزایش می‌یابد، بدون اینکه هرگز نیاز باشد آدرسی از روی ایندکس دوباره محاسبه شود:

Loop:
bge p, end_p, Exit
sd x0, 0(p)
addi p, p, 8
jal x0, Loop
Exit:

این نسخه مرحله ضرب را کاملاً حذف می‌کند، چون اشاره‌گر از قبل یک آدرس حافظه واقعی را نگه می‌دارد و فقط به یک جمع ثابت ساده برای رفتن به عنصر بعدی نیاز دارد.

چرا این تفاوت وجود دارد

یک ایندکس آرایه صرفاً یک عدد است که باید هر بار که استفاده می‌شود به یک آدرس تبدیل شود، که نیازمند ضرب در اندازه عنصر در هر دسترسی است. یک اشاره‌گر، در مقابل، از قبل یک آدرس است، پس پیش‌بردن آن به عنصر بعدی فقط نیازمند اضافه کردن یک‌باره اندازه ثابت عنصر است، نه محاسبه مجدد یک حاصل‌ضرب از ابتدا.

نتیجه عملی

کامپایلرهای بهینه‌ساز امروزی اغلب قادرند به‌طور خودکار حلقه‌های مبتنی بر ایندکس را داخلاً به حلقه‌های مبتنی بر اشاره‌گر تبدیل کنند، فرآیندی به نام Strength Reduction، که می‌تواند این شکاف کارایی را بدون نیاز به بازنویسی دستی کد توسط برنامه‌نویس از بین ببرد. با این حال، درک تفاوت زیربنایی سخت‌افزاری توضیح می‌دهد چرا از نظر تاریخی، و در مواردی که کامپایلر نمی‌تواند این بهینه‌سازی را با امنیت انجام دهد، پیمایش مبتنی بر اشاره‌گر برای کد حساس به کارایی توصیه شده است.

Written & researched by Dr. Shahin Siami

Related Articles

تصورات غلط رایج درباره محاسبات موازی و درس‌های نهایی کتاب

پس از پوشش هر چیزی از موازی‌سازی سطح رشته تا محاسبات در مقیاس انبار، ارزش دارد تصورات غلط پایداری درباره سیستم‌های موازی که حتی مهندسان باتجربه هم گاهی به آن‌ها دارند را اصلاح کنیم. این مقاله به مغالطات رایج درباره مقیاس‌پذیری و سخت‌افزار موازی می‌پردازد، سپس فصل پردازش موازی را با پیوند دادن مسیر کامل از یک دستور منفرد تا یک ساختمان پر از ماشین‌های همکار به پایان می‌رساند.

Continue

واقعیت‌های عملی: بنچمارک CPU در مقابل GPU و ضرب ماتریس چندپردازنده‌ای

مقایسه منصفانه یک CPU و یک GPU نیازمند مدلی است که هم توان عملیاتی محاسباتی و هم محدودیت‌های پهنای باند حافظه را با هم در نظر بگیرد. این مقاله مدل roofline مورد استفاده برای مقایسه سخت‌افزار واقعی مانند Intel Core i7 و NVIDIA Tesla GPU را معرفی می‌کند، سپس نشان می‌دهد ضرب ماتریس چگونه در سراسر چند پردازنده تسریع می‌شود، به‌عنوان کاربرد عملی نهایی مفاهیم موازی این فصل.

Continue

بنچمارک کردن چندپردازنده‌ها و مدل‌سازی کارایی موازی

سنجش کارایی یک سیستم موازی نیازمند ابزارها و سنجه‌های متفاوتی نسبت به سنجش یک پردازنده تک‌هسته‌ای است. این مقاله بنچمارک‌های تخصصی مورد استفاده برای ارزیابی سیستم‌های چندپردازنده را پوشش می‌دهد، توضیح می‌دهد چگونه رفتار مقیاس‌پذیری را با افزودن پردازنده‌های بیشتر مدل‌سازی کنیم، و قانون آمدال را در زمینه سنجش کارایی دنیای واقعی بازبینی می‌کند.

Continue

شبکه‌سازی کلاستر: ارتباط با دنیای بیرون

یک کلاستر از ماشین‌ها فقط زمانی مفید است که بتواند به‌طور کارآمد هم داخلی و هم با دنیای بیرون ارتباط برقرار کند. این مقاله لایه‌های شبکه‌سازی درگیر در ارتباط کلاستر، مبادلات بین تأخیر و پهنای باند در مقیاس، و اینکه کلاسترها چگونه به شبکه‌های خارجی و کاربران متصل می‌شوند را پوشش می‌دهد.

Continue

کلاسترها، کامپیوترهای در مقیاس انبار، و توپولوژی‌های شبکه

فراتر از یک تراشه واحد، موازی‌سازی به کل ساختمان‌های پر از کامپیوترهای مستقلی که با هم کار می‌کنند گسترش می‌یابد. این مقاله گذار از چندپردازنده‌سازی حافظه مشترک به کلاسترهایی از ماشین‌های جداگانه را توضیح می‌دهد، مفهوم محاسبات در مقیاس انبار را معرفی می‌کند، و توپولوژی‌های شبکه که این ماشین‌های مستقل را به‌طور کارآمد متصل می‌کنند را پوشش می‌دهد.

Continue

مقدمه‌ای بر GPU: موازی‌سازی عظیم برای بارهای کاری سنگین از نظر داده

یک GPU ایده SIMD که پیش‌تر در این مجموعه پوشش داده شد را به یک مقیاس افراطی می‌برد، و هزاران رشته سبک را به‌طور هم‌زمان اجرا می‌کند تا حجم عظیمی از داده مستقل را پردازش کند. این مقاله توضیح می‌دهد چرا GPU ها از نظر معماری این‌قدر با CPU متفاوت‌اند، مدل اجرای رشته آن‌ها چگونه کار می‌کند، و چه نوع بارهای کاری بیشترین بهره را از این طراحی می‌برند.

Continue