ايران ويج

نسخه‌ی کامل: کار با بافر و پارامتر های بی نهایت
شما در حال مشاهده‌ی نسخه‌ی متنی این صفحه می‌باشید. مشاهده‌ی نسخه‌ی کامل با قالب بندی مناسب.
صفحه‌ها: 1 2
سلام
فرض کنید که میخواهیم روی یه بافر (اشاره گر به یه چیز نا معلوم) عملیات انجام بدیم مثلا کد گذاریش کنیم چه جوری میشه؟؟؟
بعضی از توابع هستن که بی نهایت پارامتر قبول میکنن . چطوری میشه و چطوری تعداد و نوع و ... پارامتر ها رو بدست میارن؟
از آرایه ها استفاده کن
میشه بیشتر تو ضیح بدید؟
یعنی چی ؟ بافرو بریزم تو آرایه؟ آخه حجمشو ندارم که حافظه Allocate کنم
نقل قول: فرض کنید که میخواهیم روی یه بافر (اشاره گر به یه چیز نا معلوم) عملیات انجام بدیم مثلا کد گذاریش کنیم چه جوری میشه؟؟؟

اگر منظورت اشاره گر از نوع void هست باید بگم که اولش باید یک تبدیل نوع یا همون casting روی اون اشاره گر انجام بدی تا بافرت معنا پیدا کنه بعد میتونی روش عملیات انجام بدی .

نقل قول: بعضی از توابع هستن که بی نهایت پارامتر قبول میکنن . چطوری میشه و چطوری تعداد و نوع و ... پارامتر ها رو بدست میارن؟

این مسئله بستگی به نوع تابع ، نوع پارامتر ورودی و نحوه طراحیش داره . همون طور که باید بدونی پارامتر های یک تابع در زمان صدا زده شدن توی Stack Frame مخصوص اون تابع و در حافظه قرار می گیرند . اینجا دو نکته خیلی مهمه .
1 - ترتیب پارامتر ها توی Stack Frame هست ( مثلا پارامتر ها میتونن از چپ به راست یا از راست به چپ داخل stack frame قرار بگیرن )
2 - توی stack frame باید یک نشانه ای وجود داشته باشه و نمایان گر آخرین پارامتر وارد شده باشه . مثلا یک NULL در انتهای Frame میتونه به ما بگه که به آخرین پارامتر ورودی رسیدیم . ( البته همیشه نمیتونه NULL باشه چون خیلی از توابع میتونن حتی NULL رو به عنوان پارامتر قبول کنند !! ) پس پیچیدگی نحوه تشخیص انتهای لیست پارامتر ها در stack frame هست . به علت این پیچیدگی زبان C++/C راه رو برای برنامه نویسان باز گذاشته که خودشون و با مسئولیت خودشون پارامتر ها رو از Stack Frame استخراج کنند و استفاده کنند . خیلی اوقات باید از Inline Assembly استفاده کنید ( کد اسمبلی درون کد های C )
این راه کاملا پیچیده است و باید طوری توابع رو طراحی کرد این حالت پیش نیاد و گرنه بازیابی اونها در خیلی مواقع خیلی مشکل میشه ( حتی کامپایلر هم هیچ قدرتی در چک کردن مقادیر ورودی و محلشون نداره و همش بر عهده خود برنامه نویسه !)
خیلی ممنون ولی در مورد سوال اول
اشاره گر به یه String دارم و میخام اونو Decode کنم میشه؟ آخه حتی اگه Casting هم بکنم وقتی حجمشو ندونم میشه؟
آیا تابعی هست که حجم یه بافرو به من بده؟
تا حافظه Allocate کنم؟
خوب شما اونو به *char تبدیل میکنی . این رو هم خوب میدونی که انتهای یه string همیشه یک NULL هست پس خیلی راحت میتونی رشته رو تا انتها بخونی . مشکل دیگه کجاست ؟؟
تابع که نه ولی عملگری که میتونه حجم یک بافر رو به شما بده همون sizeof هست ولی اگر روی یک اشاره گر استفاده بشه حجم اشاره گر رو بهت میده نه بافری که داره بهش اشاره میکنه !
خب آخه وقتی تبدیلش میکنم باید توی یه متغیر بریزمش یانه؟
خوب اون متغیر هم باید سایزش حداقل اندازه بافره +1 باشه
یا هم منظورتون اینه که توی پارامتر های تابع تبدیلش کنم که بازم یه خورده مشکل داره
چون برای کد کردن باید بریزمش توی یه آرایه درسته؟ حجم بافر رو ندارم پس چه جوری بریزمش توی آرایه؟ (یعنی ممکنه بافر بزرگتر از آرایه باشه پس نمیشه تقریبی این کارو کرد باید حجم بافر رو بدست بیارم ، بعد با یه اشاره گر حافظه قرض بگیرم بعد تازه یه آرایه دارم که میتونم کد گزاریش کنم)
البته من یه کد دیدم که نفهمیدم چه جوری کار میکنه! توی سورس ویروس MyDoom اونم دقیقا همین کارو میکرد (رشته ها رو رمزگشایی میکرد اونم با بافر ولی نفهمیدم چه جوری!)
اینجوری میشه؟؟؟؟
کد:
int function(a[])
سلام
1-فکر کنم از CAPI استفاده کنم راحتتره!
2-تو C# یه کلمه کلیدی هست فکر کنم params که کار همین پارامتر های بی نهایت میکنه
تو C هم فکر کنم آخرش ... میزارن
یعنی تو C# راحتتر میشه این کارو کرد؟
نقل قول: خب آخه وقتی تبدیلش میکنم باید توی یه متغیر بریزمش یانه؟
خوب اون متغیر هم باید سایزش حداقل اندازه بافره +1 باشه
یا هم منظورتون اینه که توی پارامتر های تابع تبدیلش کنم که بازم یه خورده مشکل داره
چون برای کد کردن باید بریزمش توی یه آرایه درسته؟ حجم بافر رو ندارم پس چه جوری بریزمش توی آرایه؟ (یعنی ممکنه بافر بزرگتر از آرایه باشه پس نمیشه تقریبی این کارو کرد باید حجم بافر رو بدست بیارم ، بعد با یه اشاره گر حافظه قرض بگیرم بعد تازه یه آرایه دارم که میتونم کد گزاریش کنم)

ببین وقتی بهت گفتم باید به *char تبدیلش کنی واسه همین بود . همون طور که باید بدونی در زمان کامپایل تمام آرایه ها در زبان ++C/C به اشاره گر تبدیل میشن مثلا شما یه آرایه 10 خونه ای رو تعریف کن . کامپایلر بهت ایراد نمیگیره اگه شما توی خونه 15 آرایه هم یه چیزی ذخیره کنی . مثال :
کد:
int a[10];
a[15]=2;

کامپایلر خط دوم رو یه همچین چیزی فرض می کنه :

کد:
*(a+15)=10;

اینطور تصور نکن که خونه های حافظه برای یک آرایه محدود هستند . این وظیفه شماست که حدود آرایه رو حفظ کنی و این وظیفه کامپایلر نیست ( تفاوت آرایه مثلا توی VB با C همینه ) اگر مثل کدی که من بالا نوشتم شما خونه 15 رو تغییر بدی خطایی از کامپایلر دریافت نمی کنی ولی جای دیگه از حافظه رو خراب می کنی که کامپایلر برای کار دیگه ای اختصاص داده پس برنامه شما خطای منطقی پیدا می کنه !

واسه string ها هم همینطور فقط تفاوت اینه که انتهای رشته ها با یک NULL مشخصه همچنین تغییر خونه های حافظه با کمک اشاره گر ها قابل انجام شدنه و حتما نیاز به یک آرایه نیست پس لازم نیست اندازه بافر رو بدونیم . یه مثال واست میزن که روشن بشی . مثلا یک اشاره گر به یک بافر نا معلوم داریم به اسمه buf . ما میدونیم که این بافر نامعلوم یک رشته هست پس آخرش یک NULL هست . فرض کن که میخواییم همه حروف توی این رشته رو به حرف K تبدیل کنیم . کد زیر خیلی راحت اینکار رو انجام میده :


کد:
char* str=(char*)buf;
for(int i=0;str[i]!='\0';i++)
str[i]='K'

اصلا لازم نبود که طول رشته رو بدونیم . فقط ما اینقدر پیش رفتیم تا به انتهای رشته رسیدیم !
درسته ، من یه مقداری از اینا رو (90%) نمیدونستم!
من چند مدت پیش (2 سال پیش!) یه مقاله راجع به سرریز بافر خوندم فکر کنم منظورتون از خطای منطقی همین سرریز بافر هست Buffer overflow ()
خیلی خیلی ممنون
صفحه‌ها: 1 2