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

نام تاپیک: مشكل در استفاده تابعي از نوع ellipsis

  1. #1

    Tick مشكل در استفاده تابعي از نوع ellipsis

    سلام،
    تابع MyConCate به تعداد نامشخص پارامتر از نوع رشته ميگيره و كارش الحاق اين رشته هاست. پارامتر اول رشته ايه كه رشته ي ملحق شده توي اون قرار ميگيره. پارامتر آخر هم NULL است.

    void
    MyConCate(char [], ...);

    int _tmain(int argc, _TCHAR* argv[])
    {
    char Str[200];
    MyConCate(Str, "String1 ", "String2 ", "String3", NULL);
    return 0;
    }

    void MyConCate(char Str[200], ...)
    {
    char *ptrStack = &Str[99];
    int i = 0;
    ptrStack++;
    while(*ptrStack != NULL)
    {
    Str[i] = *ptrStack;
    ptrStack++;
    i++;
    }
    Str[i] = NULL;
    }


    مشكل اينه كه پارامترها پشت سر هم در استك قرار نميگيرند. براي همين نميشه به اونها دسترسي داشت.

  2. #2

    نقل قول: مشكل در استفاده تابعي از نوع ellipsis

    در ++C/C شما باید از ماکروهای اختصاص داده شده به خواندن آرگومان ها استفاده کنید یعنی :
    va_arg و va_end و va_start

    در یونیکس با هدر فایل varargs.h و در ویندوز با هر دوی stdarg.h و stdio.h

    در این لینک قبلا با مثالی توضیح داده ام:
    https://barnamenevis.org/showthread.php?p=498223

    برای توضیحات بیشتر برای هر کدام از این ماکرو ها می توانید از لینک MSDN زیر توضیحات را مشاهده کنید:
    Access variable-argument lists


    نکته: ضمنا شما می توانید به هدر فایل های آن ماکرو ها بروید و نحوه پیاده سازی آن ها را نیز مشاهده کنید.

  3. #3

    نقل قول: مشكل در استفاده تابعي از نوع ellipsis

    ولي اگر به جاي اون رشته ها عدد وارد بشه و جمع اين اعداد رو بخواهيم، مشكل نداره. چرا؟


    int
    MyAdd(int first, ...)
    {
    int *ptrStack = &first;
    int s = 0;
    while(*ptrStack)
    {
    s += *ptrStack;
    ptrStack++;
    }
    return s;
    }


    اگر مثال رشته اي درست كار نكنه، دليل نداره كه اين يكي درست كار كنه. لطفا در مورد تفاوت هاي اين دو مورد راهنماييم كنيد. ممنون.

  4. #4

    Unhappy نقل قول: مشكل در استفاده تابعي از نوع ellipsis

    توي تالار C#‎ ، سوال ها و بحث هاي تاپيك ها خيلي سريع جواب داده ميشه. ولي چرا اينجا هيچ كس جوابي نميده؟

  5. #5

    نقل قول: مشكل در استفاده تابعي از نوع ellipsis

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

    برای اینکه به پارامتر بعدی بروید همیشه نمی توانید به راحتی از ++ (یا همان به علاوه 1) استفاده کنید. این کار با توجه به معماری سخت افزاری پردازنده ها متفاو ت هست.
    مثلا برای x86 به این شکل تعریف شده است:

    #define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )

    #define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )


    ap همان ptrStack است که شما تعریف کردیه اید و آدرس اولین پارامتر در آن قرار می گیرد.
    t نیز نوع داده ای است که می خواهید بخوانید مثلا برای رشته *char و برای عدد int قرار می گیرد و سپس با توجه به فرمول _INTSIZEOF محاسبه می شود تا آدرس پارامتر بعدی بدست آید. توجه داشته باشید که اشاره گر ها هر کدام با توجه به نوعشان اندازه متفاوتی دارند.
    (در اینجا برای راحتی به جای فرمول های فوق از 4 بایت استفاده می کنیم).

    - برای گرفتن آدرس نیز باید تبدیل صریح با reinterpret_cast صورت گیرد.
    - برای گرفتن محتویات هر پارامتر نیز ابتدا آن را با ** به صورت ضمنی یعنی اشاره گر به اشاره گر تبدیل می کنیم.
    مثال زیر 4 رشته را گرفته و نمایش می دهد:

    #include <conio.h>
    #include <iostream>
    #include <stdio.h>
    #include <stdarg.h>
    #include <string.h>

    using namespace std;

    void MyConCate(char [], ...);

    int main()
    {
    char Str[200] = "hello";

    MyConCate(Str, "String1 ", "String2 ", "String3", NULL);

    printf("text:%s", Str);
    return 0;
    }

    void MyConCate(char Str[200], ...)
    {
    char* ptrStack = &reinterpret_cast<char &>(Str);

    int x = 0;
    while(x<4)
    {
    char* tempstr = (*(char **)ptrStack);
    printf("text:%s\n", tempstr);

    ptrStack += 4; // always not like this
    x++;
    }
    getch();
    }

  6. #6

    نقل قول: مشكل در استفاده تابعي از نوع ellipsis

    سلام. ممنون از پاسختون. راستش من دقت كردم و پست شما رو خوندم. ولي شايد مشكل از بي سوادي منه (چون زياد چيزي كه بدردم بخوره و دنبالش باشم دستگيرم نشد.)

    الان هم دو تا سوال دارم ازتون:

    (در اینجا برای راحتی به جای فرمول های فوق از 4 بایت استفاده می کنیم).
    1- چرا 4 بايت؟ از كجا به اين نتيجه رسيديد؟ (شايد سوالم پيش پا افتاده باشه! واقعا متوجه نشدم!)

    2- به جواب سوال قبليم هم نرسيدم! شما گفتيد كه:
    برای اینکه به پارامتر بعدی بروید همیشه نمی توانید به راحتی از ++ (یا همان به علاوه 1) استفاده کنید.
    ميخواستم بدونم كه اينكه پارامترها عدد باشه يا رشته، چه فرقي داره كه رشته جواب نميده ولي براي عدد روش ++ جواب ميده؟

    ببخشيد كه سرتون رو درد اوردم.
    پيشاپيش از جوابتون ممنونم.

  7. #7

    نقل قول: مشكل در استفاده تابعي از نوع ellipsis

    1- وقتی شما از عملگر ++ استفاده می کنید به اندازه نوع داده ای که به آن اشاره می کند بایت اضافه می کند. یعنی وقتی ptrStack شما به یک char که فقط یک بایت است اشاره می کند پس با ++ یک بایت به آن اضافه می شود، در حالی که آدرس ها در این نمونه مثال ما 4 بایتی هستند. (اما در هر حال من این عدد را از همان فرمول بدست آوردم)

    نکته: در بخش سورس کدها نوشته شده است بر اساس معماری Intel این مقدار به ضریبی از 4 گرد می شود.

    برای اینکه برای هر نوعی و هر سیستمی بتوانید این مقدار را محاسبه کنید از فرمول های مشابه ذکر شده در پست قبلی استفاده کنید و خودتان ++ ننویسید. یا کلا از ماکروها ذکر شده استفاده کنید.

    2- در مثال int شما ، ptrStack به یک int اشاره می کند (برخلاف مثال قبلی شما که *char برای رشته ها بود)، پس وقتی می نویسید ++ptrStack یعنی 4 واحد به آن اضافه می شود و برعکس رشته ها درست عمل می کند. ضمنا کلا کد نوشته شده برای رشته های شما غلط بود.

    int *ptrStack = &first;

    char *ptrStack = &Str[99]; // worng code
    char* ptrStack = &reinterpret_cast<char &>(Str);
    پس با تمام این تفاسیر چه برای *char و چه *int شما باید 4 بایت اضافه کنید تا به آدرس بعدی برود.

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

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