نمایش نتایج 1 تا 6 از 6

نام تاپیک: یک راه حل در اشغال رم(ارسال رشته)

  1. #1

    یک راه حل در اشغال رم(ارسال رشته)

    سلام به همه و عید فطر مبارک
    در برنامه نویسی به موضوعی برخورد کردم که تابحال راه حل ساده ای براش پیدا نکردم!
    تابع زیر رو در نظر بگیرید: (تابعی جهت ارسال یک رشته)
     
    void send_str(char *const pStr, const int lenStr);

    یه تابع ساده که دوتا آرگومان داره:
    اولی یک اشاره گر به یک رشته هستش. (اون کلمه const که بعد از علامت “*” اومده باعث میشه از تغییر دادن آدرس درون اشاره گر جلوگیری بشه تا مطمئن باشیم به طور اشتباهی درون تابع آدرس اشاره گر تغییر نمیکنه)
    دومی طول دیتا جهت ارسال رو مشخص میکنه.

    -----------------------------
    مشکل: وقتی از این تابع به شکل زیر استفاده بشه:

    send_str( “salam”, 5);


    رشته salam ارسال میشه و به میزان 5 Byte از ram اشغال میشه.
    حالا اگر دوبار از این تابع استفاده بشه:

    send_str( “salam”, 5);
    send_str( “salam”, 5);


    رشته salam دو بار ارسال میشه اما این بار 10 Byte از Ram اشغال میشه.
    درواقع پس از هر بار استفاده از این تابع شاهد این هستیم که ram اشغالی هم افزایش پیدا میکنه.
    برای رفع این مشکل اشغال زیاد ram اومدم یه رشته به طول طولانی ترین متن ایجاد کردم و هر بار که قصد ارسال متنی رو دارم اول اون متن رو به صورت کاراکتر به کاراکتر درون اون رشته قرار میدم وبعد اراسل میکنم.
    اینجوری تنها به اندازه اون رشته فضای ram اشغال شده.
    مثال از این روش:

    char mainStr[10] = “123”; //10 Byte use of Ram
    send_str( mainStr, 3); //not need to use new Ram.
    str[0] = ‘s’;
    str[1] = ‘a’;
    str[2] = ‘l’;
    str[3] = ‘a’;
    str[4] = ‘m’;
    send_str( mainStr, 5); //not need to use new Ram.
    send_str( mainStr, 5); //not need to use new Ram.


    مزیت این کار: اشغال شدن ram تنها به اندازه رشته ای که برای ارسال متن ها ساختیم.
    عیب کار: وقتی با یه متن طولانی روبه رو میشیم بار گذاری اون متن طولانی درون رشته خیلی وقت گیر هست.(فکر کنید بخوایم 200 متن 300 کاراکتری رو ارسال کنیم)

    دوستان راه حلی برای این هست که بشه به شیوه دیگه ای این کار رو کرد تا رم زیادی اشغال نشه و تا این حد هم استفاده وقت گیر نشه؟

  2. #2

    Post نقل قول: یک راه حل در اشغال رم(ارسال رشته)

    سلام
    یک راه استفاده از ارایه ایستا کاراکتری هست:
    char ptr[] = "abcd";

    راه دیگه استفاده از ارایه پویا کاراکتری :
    توابع malloc و free
    با تابع strncpy هم میتونید متنی دلخواه درون ارایه قرار بدید و بعد به عنوان پارامتر به تابع خودتون ارسال کنید:
    char src[40]; 
    strcpy(src, "This is test");

  3. #3

    نقل قول: یک راه حل در اشغال رم(ارسال رشته)

    نقل قول نوشته شده توسط pe32_64 مشاهده تاپیک
    سلام
    یک راه استفاده از ارایه ایستا کاراکتری هست:
    char ptr[] = "abcd";

    راه دیگه استفاده از ارایه پویا کاراکتری :
    توابع malloc و free
    با تابع strncpy هم میتونید متنی دلخواه درون ارایه قرار بدید و بعد به عنوان پارامتر به تابع خودتون ارسال کنید:
    char src[40]; 
    strcpy(src, "This is test");
    متشکرم
    چون برنامه نویسی برای میکروکنترلر هست سعی میکنم از دستوراتی مثل strcpy() استفاده نکنم چون زمان بیشتری از مقدار دهی مستقیم نیاز داره.
    اصل به توابع malloc و free توجه نکرده بودم، اشاره خیلی عالی کردین بازم ممنونم

  4. #4

    نقل قول: یک راه حل در اشغال رم(ارسال رشته)

    اول شما مشخص نکردید که برای چه معماری برنامه مینویسید؟ CISC or RISC
    بنابراین من فرض میگرم شما برای پردازشگرهای CISC برنامه می نویسید
    send_str( “salam”, 5);
    زمانی که تابع فوق را به این صورت فراخوانی میکنید، کامپایلر برای رشته "salam" یک آفست آدرس تولید میکنه که این آفست آدرس را در محل آفست آدرس اشاره گر *char قرار میده، و وقتی شما از یک مقدار temporary که توسط کامپایلر ایجاد شده جهت استفاده از رشته salam استفاده میکنید بنابراین برای بار دوم هم کامپایلر مجدد این آدرس افست را ایجاد میکنه با اینکه ظاهرا رشته تکراری هستش با اینکه ظاهرا شما در یک حوزه دید از این دوتابع استفاده کردید.(البته بدون در نظر گرفتن optimization کامپایلر ) پس مدیریت stack frame تابع به عهده کامپایلر هستش، برای اینکه بخواهید از یک حافظه کمتر استفاده کنید...
    1- رشته salam را در یک متغیر صریح مقدار دهی کنید، تا اینطوری کامپایلر فقط یک آفست آدرس ایجاد کنه
    2- در معماری که برنامه مینویسید براساس 16 , 32 , 64 حتما توجه کنید که طول رشته ثابت را ضریبی از مقدار بیت های معماری در نظر بگیرید تا اینطوری از هدر رفتن حافظه جلوگیری کنید، به عنوان مثال اگر 32 بیت کار میکنید سعی کنید طول رشته ثابت قابل تقسیم شدن به 32 باشه الان رشته salam + null pointer میشه 6 که تقریبا 2 بایت هدر رفت حافظه داریم( حالا چرا چون آدرس های حافظه در معماری 32 بیتی باید ضریبی از 32 باشند به همین علت کامپایلر برای آدرس دهی 6 بایت از 2 آدرس 4 بایتی استفاده میکنه)

    در ضمن استفاده از حافظه هیپ هم کندتر از stack هستش به همین علت اگر اندازه آرایه رشته ای را از ابتدا به درستی تعیین کنید هم سرعت بیشتری خواهید داشت وهم هدر رفت حافظه ای کمتری خواهید داشت
    آخرین ویرایش به وسیله farhad_shiri_ex : یک شنبه 22 تیر 1399 در 10:39 صبح

  5. #5

    نقل قول: یک راه حل در اشغال رم(ارسال رشته)

    نقل قول نوشته شده توسط farhad_shiri_ex مشاهده تاپیک
    اول شما مشخص نکردید که برای چه معماری برنامه مینویسید؟ MISC or SISC
    بنابراین من فرض میگرم شما برای پردازشگرهای MISC برنامه می نویسید

    زمانی که تابع فوق را به این صورت فراخوانی میکنید، کامپایلر برای رشته "salam" یک آفست آدرس تولید میکنه که این آفست آدرس را در محل آفست آدرس اشاره گر *char قرار میده، و وقتی شما از یک مقدار temporary که توسط کامپایلر ایجاد شده جهت استفاده از رشته salam استفاده میکنید بنابراین برای بار دوم هم کامپایلر مجدد این آدرس افست را ایجاد میکنه با اینکه ظاهرا رشته تکراری هستش با اینکه ظاهرا شما در یک حوزه دید از این دوتابع استفاده کردید.
    پس مدیریت stack frame تابع به عهده کامپایلر هستش، برای اینکه بخواهید از یک حافظه کمتر استفاده کنید...
    1- رشته salam را در یک متغیر صریح مقدار دهی کنید، تا اینطوری کامپایلر فقط یک آفست آدرس ایجاد کنه
    2- در معماری که برنامه مینویسید براساس 16 , 32 , 64 حتما توجه کنید که طول رشته ثابت را ضریبی از مقدار بیت های معماری در نظر بگیرید تا اینطوری از هدر رفتن حافظه جلوگیری کنید، به عنوان مثال اگر 32 بیت کار میکنید سعی کنید طول رشته ثابت قابل تقسیم شدن به 32 باشه الان رشته salam + null pointer میشه 6 که تقریبا 2 بایت هدر رفت حافظه داریم( حالا چرا چون آدرس های حافظه در معماری 32 بیتی باید ضریبی از 32 باشند به همین علت کامپایلر برای آدرس دهی 6 بایت از 2 آدرس 4 بایتی استفاده میکنه)

    در ضمن استفاده از حافظه هیپ هم کندتر از stack هستش به همین علت اگر اندازه آرایه رشته ای را از ابتدا به درستی تعیین کنید هم سرعت بیشتری خواهید داشت وهم هدر رفت حافظه ای کمتری خواهید داشت
    از معماری RISC استفاده میکنم.
    توی این انجمن عجب برنامه نویسایی داریم آدم لذت میبره، توضیحات شما خیلی عالی بود
    ------
    1- تنها راه حذف این حافظه temporary پس از استفاده خروج از تابع هستش؟
    2- راهی هست که بشه از همون آدس افست قبلی دوباره استفاده بشه برای زمانی که چندین بار در یک تابع از تابعی مثل

    send_str( “salam”, 5);

    استفاده شده باشه؟

    3- دوست عزیز میشه منبعی برای توضیح حافظه هیپ بهم معرفی کنی یا خودتون یه توضیحی بدید.

    پیشاپیش متشکرم

  6. #6

    نقل قول: یک راه حل در اشغال رم(ارسال رشته)

    نقل قول نوشته شده توسط kenshin مشاهده تاپیک
    از معماری RISC استفاده میکنم.
    توی این انجمن عجب برنامه نویسایی داریم آدم لذت میبره، توضیحات شما خیلی عالی بود
    ------
    1- تنها راه حذف این حافظه temporary پس از استفاده خروج از تابع هستش؟
    2- راهی هست که بشه از همون آدس افست قبلی دوباره استفاده بشه برای زمانی که چندین بار در یک تابع از تابعی مثل

    send_str( “salam”, 5);

    استفاده شده باشه؟

    3- دوست عزیز میشه منبعی برای توضیح حافظه هیپ بهم معرفی کنی یا خودتون یه توضیحی بدید.

    پیشاپیش متشکرم
    ببخشیذ که دیر جواب میدم

    سوال 1
    حافظه temp معمولا در stack frame خود تابع ساخته میشه که بعد از خارج شدن از تابع کامپایلر چون stack را تراز میکنه پس اون حافظه به منابع سیستم برمیگرده! البته به شرطی که از هیپ استفاده نکرده باشید! در اینصورت وظیفه بازپس گیری منابع حافظه ای را خودتون باید کنترل کنید
    سوال 2
    بله اگر از استاندارد های جدید زبان مثل 11 به بعد استفاده کنید عملگر جدیدی اضافه شده (&&)Rvalue که دقیقا برای همین مکانیزم طراحی شده که بتونید به اون آفست Temp دسترسی داشته باشید،
    یک نکته ای که خیلی مهمه درباره رفتار کامپایلر های که با RISC سازگار هستند، RAM-Ability یا ROM-Ability بودن اعلام رشته ها هستش مثلا...
    تصور کنید با دستور زیر

    ;("const std::string tempStr = ("1.23

    وقتی چنین تعریفی استفاده میکنید معمولا کامپایلر یک رشته ثابت که در حافظه stack تخصیص داده شده استفاده میکنه که بهش میگیم تعریف نوع در زمان اجرا یا همان Ram Ability
    حالا اگر چنین چیزی تعریف کنید...

    const std::array<char, 5U> version_string2
    {
    { ’1’, ’.’, ’2’, ’3’, ’\0’ }
    };

    بنابراین با تعریف چنین رشته ای کامپایلر رشته مورد نظر را در زمان کامپایل در یک section .readonly ذخیره میکنه و هرجا که لازم باشه آدرسی که relocate شده استفاده میکنه! بنابراین به این نوع از تعریف رشته ثابت Rom Ability گفته میشه که دیگه overhead تعریف رشته اول را نداره! البته در استاندارد های جدیدتر بهتره که از constexpr بجای const استفاده کنید کارایی بیشتری در زمان کامپایل خواهید داشت.

    سوال 3
    البته منبع برای heap که خیلی زیاده، ولی خیلی خلاصه بخواهم بگم...
    حافظه ای پویا که معمولا به عنوان حافظه بدون محدودیت ازش یاد میکنیم، یعنی اندازه این حافظه توسط سیستم عامل کنترل میشه! ولی تعریف متغیر در این حافظه توسط برنامه نویس انجام میشه! والبته برنامه نویس هم همیشه باید توجه داشته باشه که وظیفه بازپس گیری مجدد منابعی که از این حافظه استفاده کرده را داره! بنابراین در صورت فراموش کردن این بازپس گیری اون قسمت از حافظه توسط سیستم عامل دیگه قابل استفاده نخواهد بود بنابراین برای اینکه خیلی راحت و سر راست از این حافظه استفاده کنید بهتره از smart pointer ها استفاده کنید البته در برنامه نویسی با میکروها معمولا استفاده از هیپ مجاز نیست برای همین از روش های static memory استفاده میشه که در استانداردهای جدید از کلاسهایی مانند https://en.cppreference.com/w/cpp/utility/variant)std::variant) استفاده میشه که کارایی بالاتری داره
    و منابع معتبر برای Heap
    https://en.cppreference.com/w/cpp/me...w/operator_new


قوانین ایجاد تاپیک در تالار

  • شما نمی توانید تاپیک جدید ایجاد کنید
  • شما نمی توانید به تاپیک ها پاسخ دهید
  • شما نمی توانید ضمیمه ارسال کنید
  • شما نمی توانید پاسخ هایتان را ویرایش کنید
  •