اطلاعیه

Collapse
No announcement yet.

ترفند هائی در برنامه نویسی c و ++c

Collapse
X
 
  • فیلتر
  • زمان
  • Show
Clear All
new posts

    ترفند هائی در برنامه نویسی c و ++c

    با سلام.
    توی این تاپیک سعی میکنم نکاتی را در مورد برنامه نویسی c برای AVR که کمتر در موردش صحبت میشه توضیح دهیم

    اولین نکته ای که به ذهنم میرسه در مورد اشاره گرهای به توابع هست
    در AVR اشاره گرهای به توابع به حافظه فلش اشاره میکنند
    به عنوان مثال کد زیر باعث میشود که برنامه به آدرس 0 (RESET) حافظه فلش پرش کند : و به این ترتیب میکرو به صورت نرم افزاری ریست میشود.

    ;void (*function)(void) = 0x0000


    میتوانیم به جای 0000 هر آدرسی که خواستیم بگذاریم. به عنوان مثال میتوانیم آدرس شروع برنامه Bootloader را بگذاریم و از داخل Application به بوتلودر پرش کنیم.

    شاید هم بتوانیم 2 برنامه مجزا بنویسیم و در 2 آدرس مختلف فلش ذخیره کنیم و به هر کدام که خواستیم پرش کنیم
    البته درستی این مطلب را نمیدانم و شاید بهتر باشه یکی از اساتید آن را تائید کند

    #2
    پاسخ : ترفند هائی در برنامه نویسی c و ++c

    همیشه برای انتخاب نوع متغیرها سعی کنید کوچکترین نوع ممکن را انتخاب کنید.
    به عنوان مثال برای ذخیره محتوای یک رجیستر 8 بیتی (مثلا PORTD یا UDR) متغیر از نوع unsigned char تعریف شود. سایز انواع نوعها

    signed char / unsigned char : 8-bit
    signed int / unsigned int : 16-bit
    signed long / unsigned long : 32-bit
    signed long long / unsigned long long : 64-bit

    سایز نوعها به صورت کامل در فایل stdint.h قابل مشاهده میباشد

    مثال:

    استفاده از Unsigned int : (سایز 92 بایت)
    کد:
    () unsigned int readADC
    }
    ;return ADCH
    {
    (int main(void
    {
    ;()unsigned int mAdc = readADC
    {

    استفاده از Unsigned char: (سایز 90 بایت)

    کد:
    () unsigned char readADC
    }
    ;return ADCH
    {
    (charmain(void
    {
    ;()unsigned char mAdc = readADC
    }

    دیدگاه


      #3
      پاسخ : ترفند هائی در برنامه نویسی c و ++c

      تعریف متغیرها به صورت Global یا Local :

      در اکثر مواقع استفاده از متغیرهای Global توصیه نمیشود و تا جائی که میشه باید از متغیرهای Local استفاده کرد. در واقع انتخاب متغیر عمومی و یا محلی بستگی به نوع کاربرد آن متغیر دارد.
      زمانی که یک متغیر به صورت Global تعریف میشود - در زمان لینک شدن برنامه یک آدرس مطلق و منحصر به فرد در Sram به آن اختصاص داده میشود و همچنین دسترسی به متغیرهای عمومی به 2 بایت آدرس نیاز دارد.

      اما متغیر های Local در زمان کامپایل در صورت امکان در یکی از رجیسترهای کاری و یا در stack ذخیره میشوند. زمانی که تابع صدا زده میشوند متغیرهای محلی تابع فعال میشوند و زمانی که کار تابع به پایان میرسد متغیرهای آن از بین میروند.


      مثال استفاده از متغیر به صورت Global. حجم کد برنامه 104 بایت. sram مصرف شده 1 بایت :
      کد:
      ;unsigned int global_1
      (int main(void
      }
      ;global_1 = 0xAA
      ;PORTB = global_1
      {


      مثال استفاده از متغیر به صورت Local. حجم کد برنامه 84 بایت. sram مصرف شده 0 بایت :
      کد:
      (int main(void
      }
      ;unsigned int global_1
      ;global_1 = 0xAA
      ;PORTB = global_1
      {

      دیدگاه


        #4
        پاسخ : ترفند هائی در برنامه نویسی c و ++c

        در زمان استفاده از حلقه ها مانند while و یا for ما عموما مقدار این ایندکس حلقه را در حالت افزایشی قرار میدهیم ولی بهتر است مقدار ایندکس به صورت کاهشی باشد

        دلیل :
        زمانی که ایندکس حلقه به صورت افزایشی است - همیشه مقدار کنونی ایندکس باید با بالاترین مقدار حلقه مقایسه شود تا مشخص شود حلقه چه زمانی به پایان میرسد ولی در حالت کاهشی این مقایسه لازم نیست زیرا زمانی که مقدار حلقه به صفر برسد فلگ Z در رجیستر SREG یک میشود

        مثال حالت افزایشی(increment) - حجم کد 96 بایت :
        کد:
        (int main(void
        }
        ;unsigned int local_1 = 0
         do 
        }
        ;PORTB ^= 0x01
        ;++local_1
        ;(while (local_1<100{
        {


        مثال حالت کاهشی(decrement)- حجم کد 94 بایت :

        کد:
        (int main(void
        }
        ;unsigned int local_1 = 100
         do 
        }
        ;PORTB ^= 0x01
        ;--local_1
        ;(while (local_1{
        {

        دیدگاه


          #5
          پاسخ : ترفند هائی در برنامه نویسی c و ++c

          یک مساله که خیلی وقتها باعث بوجود آمدن باگ در برنامه میشه استفاده از عملگر انتساب (=) به جای عملگر مقایسه (==) در دستورات شرطی هست

          به عنوان مثال نوشتن (if (i=30 به جای (if (i==30 - اگر چنین اشتباهی در نوشتن کد پیش آید کامپایلر بدون هیچ اروری کد شما را کامپایل میکند در حالی که منطق برنامه کاملا عوض میشود و اگر کد شما حجیم باشد (مثلا 5000 خط کد) شما مجبورید مدت بسیار زیادی را برای پیدا کردن باگ برنامه صرف کنید.

          یک عادت بسیار خوب برنامه نویسی وجود دارد که باعث از بین رفتن بروز چنین اشتباهی میشود.
          اگر شما مقدار ثابت را در سمت چپ بنویسید یعنی به این صورت : (if (30==i دیگر امکان ایجاد باگ از بین میرود. زیرا اگر در این کد اشتباها به جای عملگر مقایسه(==) از عملگر انتساب (=) استفاده کنید کامپایلر یک اررور تولید میکند.

          دیدگاه


            #6
            پاسخ : ترفند هائی در برنامه نویسی c و ++c

            نوشته اصلی توسط M-taheri
            یک مساله که خیلی وقتها باعث بوجود آمدن باگ در برنامه میشه استفاده از عملگر انتساب (=) به جای عملگر مقایسه (==) در دستورات شرطی هست

            به عنوان مثال نوشتن (if (i=30 به جای (if (i==30 - اگر چنین اشتباهی در نوشتن کد پیش آید کامپایلر بدون هیچ اروری کد شما را کامپایل میکند در حالی که منطق برنامه کاملا عوض میشود و اگر کد شما حجیم باشد (مثلا 5000 خط کد) شما مجبورید مدت بسیار زیادی را برای پیدا کردن باگ برنامه صرف کنید.

            یک عادت بسیار خوب برنامه نویسی وجود دارد که باعث از بین رفتن بروز چنین اشتباهی میشود.
            اگر شما مقدار ثابت را در سمت چپ بنویسید یعنی به این صورت : (if (30==i دیگر امکان ایجاد باگ از بین میرود. زیرا اگر در این کد اشتباها به جای عملگر مقایسه(==) از عملگر انتساب (=) استفاده کنید کامپایلر یک اررور تولید میکند.

            سلام

            ممنون
            من هنوز برام جای سوال است چرا اررور نمی گیرد در شرط "if" که به متغییر مقدار نمی دهند ؟

            دیدگاه


              #7
              پاسخ : ترفند هائی در برنامه نویسی c و ++c

              نوشته اصلی توسط M-taheri
              اولین نکته ای که به ذهنم میرسه در مورد اشاره گرهای به توابع هست
              در AVR اشاره گرهای به توابع به حافظه فلش اشاره میکنند
              به عنوان مثال کد زیر باعث میشود که برنامه به آدرس 0 (RESET) حافظه فلش پرش کند : و به این ترتیب میکرو به صورت نرم افزاری ریست میشود.
              ;void (*function)(void) = 0x0000
              میتوانیم به جای 0000 هر آدرسی که خواستیم بگذاریم. به عنوان مثال میتوانیم آدرس شروع برنامه Bootloader را بگذاریم و از داخل Application به بوتلودر پرش کنیم.
              شاید هم بتوانیم 2 برنامه مجزا بنویسیم و در 2 آدرس مختلف فلش ذخیره کنیم و به هر کدام که خواستیم پرش کنیم
              البته درستی این مطلب را نمیدانم
              میدونید که هنگام فراخوانی توابع آدرس بازگشت داخل پشته ذخیره میشه. یعنی ممکنه بعد از چند بار ریست از این نوع؛ پشته پر بشه و معلوم نیست چه اتفاقی میفته!!
              من به جای اینکار دو راه رو پیشنهاد میکنم
              1- استفاده مستقیم از دستورات jump اسمبلی میکرو
              2- استفاده از WDT و موقعی که میخوایم میکرو رو ریست کنیم ؛ برای چند لحظه شمارنده واچ داگ رو بی خیال شیم خودش ریست میشه
              در ضمن برای مورد اول میشه مثلا برای بوت لودر هم استفاده کرد (که البته اینکار هم انجام شده)

              دیدگاه


                #8
                پاسخ : ترفند هائی در برنامه نویسی c و ++c


                سلام

                ممنون
                من هنوز برام جای سوال است چرا اررور نمی گیرد در شرط "if" که به متغییر مقدار نمی دهند ؟
                نوشتن کد به صورت (if (i=30 باعث میشود که مقدار 30 در متغیر i قرار گیرد و چون این مقدار به درستی در متغیر i قرار میگیرد شرط همیشه درست ارزیابی میشود

                دیدگاه


                  #9
                  پاسخ : ترفند هائی در برنامه نویسی c و ++c

                  نوشته اصلی توسط M-taheri
                  نوشتن کد به صورت (if (i=30 باعث میشود که مقدار 30 در متغیر i قرار گیرد و چون این مقدار به درستی در متغیر i قرار میگیرد شرط همیشه درست ارزیابی میشود
                  در ربان c عدد 0 نشوندهنده نادرستی و هر عدد دیگه ای نشوندهنده درستی هست

                  دیدگاه


                    #10
                    پاسخ : ترفند هائی در برنامه نویسی c و ++c

                    نوشته اصلی توسط mojalan
                    - استفاده مستقیم از دستورات jump اسمبلی میکرو
                    چرا از دستور goto زبان c استفاده نکنیم؟

                    دیدگاه


                      #11
                      پاسخ : ترفند هائی در برنامه نویسی c و ++c

                      اولا که با دسور goto فقط میتوان داخل کد پرش کرد ولی با دستور jmp یا rjmp میتوان به آدرسی مشخص از حافظه فلش پرش کرد. و منظور ما در اینجا پرش به آدرسهای حافظه فلش هست.

                      دوما ازنقطه نظر کسی که تحلیل الگوریتم را به خوبی فرا گرفته چیزی به مفهوم goto اصلا وجود ندارد که بخواهد با چیز دیگری جایگزین شود! اما در سادهآ‌ترین حالت میآ‌توان آن را با یک دستور شرطی (if) جایگزین کرد. در کل این دستور اشکالزدائی و بهینه کردن کد را هم مشکل میکند

                      دیدگاه


                        #12
                        پاسخ : ترفند هائی در برنامه نویسی c و ++c

                        نوشته اصلی توسط mojalan
                        میدونید که هنگام فراخوانی توابع آدرس بازگشت داخل پشته ذخیره میشه. یعنی ممکنه بعد از چند بار ریست از این نوع؛ پشته پر بشه و معلوم نیست چه اتفاقی میفته!!
                        من به جای اینکار دو راه رو پیشنهاد میکنم
                        1- استفاده مستقیم از دستورات jump اسمبلی میکرو
                        2- استفاده از WDT و موقعی که میخوایم میکرو رو ریست کنیم ؛ برای چند لحظه شمارنده واچ داگ رو بی خیال شیم خودش ریست میشه
                        در ضمن برای مورد اول میشه مثلا برای بوت لودر هم استفاده کرد (که البته اینکار هم انجام شده)
                        آیا زمانی که به آدرس 0000 پرش میکنیم و میکرو ریست میشود محتویات stack ریست نمیشوند؟ تا آنجائی که من میدونم در ابتدای برنامه اسمبلی آدرس انتهای sram در رجیستر اشاره گر پشته (sp) قرار میگیرد. و وقتی ما به آدرس 0 پرش میکنیم این مقدار دهی دوباره انجام میشود پس در واقع این باعث پر شدن پشته نخواهد شد

                        دیدگاه


                          #13
                          پاسخ : ترفند هائی در برنامه نویسی c و ++c

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

                          دیدگاه


                            #14
                            پاسخ : ترفند هائی در برنامه نویسی c و ++c

                            نوشته اصلی توسط M-taheri
                            اولا که با دسور goto فقط میتوان داخل کد پرش کرد ولی با دستور jmp یا rjmp میتوان به آدرسی مشخص از حافظه فلش پرش کرد. و منظور ما در اینجا پرش به آدرسهای حافظه فلش هست.

                            دوما ازنقطه نظر کسی که تحلیل الگوریتم را به خوبی فرا گرفته چیزی به مفهوم goto اصلا وجود ندارد که بخواهد با چیز دیگری جایگزین شود! اما در سادهآ‌ترین حالت میآ‌توان آن را با یک دستور شرطی (if) جایگزین کرد. در کل این دستور اشکالزدائی و بهینه کردن کد را هم مشکل میکند
                            بله درسته ولی دستور goto هم برای حالت خاص در نظر گرفته شده و کاربردش برای خروج از چند حلقه تو در تو هست

                            دیدگاه

                            لطفا صبر کنید...
                            X