رفتن به مطلب
مرجع رسمی سی‌پلاس‌پلاس ایران

قاسم رمضانی منش

مدیران مرجع
  • تعداد ارسال ها

    97
  • تاریخ عضویت

  • روز های برد

    25

پست ها ارسال شده توسط قاسم رمضانی منش


  1. در ۱ ساعت قبل، Heydar Mahmoodi گفته است :

    سلام
    وقتتون بخیر
    میشه بگید آخرش چیو انتخاب کردید و چرا؟
    کلا تجربه تون راجب اون پروژه درمورد دیتابیسش رو میشه عرض کنید؟

    سلام و درود؛ 

    دیتابیس MySQL انتخاب شد، امّا برنامه‌نویس اون قسمت من نبودم.

    • پسندیدن 1

  2. @axarbani  با سلام؛ 

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

    اوّل اینکه Header fileی که پیشنهاد کردید (conio.h) یک Header file منسوخ شدهٔ زمان MS-DOS برای هست که نمی‌دونم برای چی هنوز روی سیستم‌عامل Microsoft Windows هست و استفاده از این Header file‌ نه تنها از خوانایی برنامهٔ شما کم می‌کنه بلکه قابلیّت Code portability رو هم از دست میدید و برنامه‌اتون صرفاً برای یک پلتفرم قابل کامپایل خواهد بود. پیشنهاد می‌کنم که از یک روش مطابق با Standard پی‌روی کنید مثلاً به جای استفاده از تابع getch() می‌تونید از std::cin.get() استفاده کنید.

    و مورد دوّم، متغیرهایی که استفاده‌ای ازشون ندارید رو تعریف نکنید اینطوری باعث میشه که Compiler الکی Warning به شما بده. اکثراً استفاده‌ای از متغیرهای Command lineی که برای تابع main() ارسال میشه نداریم.

    • پسندیدن 1

  3. سلام و درود بر شما؛

    خب شما باید از اون APIهایی که دو پروژهٔ مختلف به‌شما می‌دهند استفاده کنید، و  فقط یک تابع Main را نگه‌داری کنید. برای مثال، ما دو Source code داریم که به این‌صورت تعریف شده‌اند:

    main_1.cpp:

    #include <algorithm>
    #include <iostream>
    #include <vector>
    
    using vec_int = std::vector<int>;
    
    void print_vector(const vec_int& in)
    {
        std::for_each(in.begin(), in.end(), [](const auto& i) { std::cout << i << std::endl; });
    }
    
    int main(void)
    {
        vec_int my_vec(10);
        print_vector(my_vec);
    }
    

     

    و یک Source code دیگر:

    main_2.cpp:

    #include <algorithm>
    #include <iostream>
    #include <vector>
    #include <ctime>
    
    using vec_int = std::vector<int>;
    
    void initilization_vector(vec_int& in)
    {
        std::srand(std::time(nullptr));
    
        std::generate(in.begin(), in.end(), []() { return std::rand() % 100; });
    }
    
    int main(void)
    {
        vec_int my_vec(10);
        initilization_vector(my_vec);
    }
    

     

    حالا برای اینکه‌ما بتوانیم از APIهای این Source codeها استفاده کنیم ابتدا یک Header file درست می‌کنیم و اعلان‌های APIهای مورد نظرمان را داخل آن می‌نویسیم:

    my_api.h:

    #ifndef MY_API_H
    #define MY_API_H
    
    #include <algorithm>
    #include <iostream>
    #include <vector>
    #include <ctime>
    
    using vec_int = std::vector<int>;
    
    namespace api
    {
    void print_vector(const vec_int& in);
    void initilization_vector(vec_int& in);
    } // namespace api
    
    #endif // MY_API_H
    

    همچنین برای تعاریف از یک Source file دیگر استفاده می‌کنیم:

    my_api.cpp:

    #include "my_api.h"
    
    void api::print_vector(const vec_int &in)
    {
        std::for_each(in.begin(), in.end(), [](const auto &i) { std::cout << i << std::endl; });
    }
    
    void api::initilization_vector(vec_int &in)
    {
        std::srand(std::time(nullptr));
    
        std::generate(in.begin(), in.end(), []() { return std::rand() % 100; });
    }
    

    حال به راحتی می‌توانیم در پروژهٔ تازه ایجاد کردهٔ خودمان از این APIهایی که از دو Source code مختلف با دو Main جدا جمع‌آوری شده را استفاده کنیم:

    main.cpp:

    #include "my_api.h"
    
    int main(void)
    {
        vec_int my_vec(10);
    
        api::initilization_vector(my_vec);
        api::print_vector(my_vec);
    }
    

     

    نمایی از محیط Code::blocks برای پروژهٔ بالا:

    image.thumb.png.bb34f5bdf0584094e35298b90375cf0e.png


  4. خواهش می‌کنم؛ خب آره همینی هست که گفته‌‌ام، نمی‌دونم بیرونی‌ترین شئ منظورت چیه ؟ ساختار QML درختی هست یعنی اینکه یک Root داره و میاد همینطوری پایین و شما کلاً یک Root هم بیشتر ندارید. شما اگه بیاید اون Rectangle رو داخل یک Item دیگه بزارید درواقع یک کامپوننتی دارید که قابلیّت‌های Rectangle رو هم داره اینطوری :

    AnotherRectangle.qml

    import QtQuick 2.0
    import QtQuick.Controls 2.0
    
    Item
    {
        property alias rectangleId : recId;
    
        Rectangle
        {
            id: recId
        }
    }
    

     

    main.qml

    import QtQuick 2.13
    import QtQuick.Window 2.13
    
    Window
    {
        visible: true
        width: 640
        height: 480
    
        AnotherRectangle
        {
            anchors.centerIn: parent
    
            width: parent.width / 2
            height: parent.height / 2
    
            rectangleId.color: "Red"
            rectangleId.width: 100
            rectangleId.height: 200
        }
    
    }
    

    image.png.c6c4f1c9f9ca50164faea3a0c8e95ccf.png

    • تشکر شده 1

  5. سلام؛ فکر کنم منظورتون این باشه :

    AnotherRec.qml

    import QtQuick 2.0
    
    Rectangle
    {
    }
    

    main.qml

    import QtQuick 2.13
    import QtQuick.Window 2.13
    
    Window
    {
        visible: true
        width: 640
        height: 480
    
        AnotherRec
        {
            anchors.centerIn: parent;
    
            width: parent.width / 2;
            height: parent.height / 2;
            color: "gray";
        }
    
    }
    

     

    که اینجا ما یک کامپوننت جدیدی درست کردیم که از Rectangle به ارث برده، بد نیست اون مستنداتی هم که خوندید رو ارسال کنید شاید بحث کلاً یه چیز دیگه‌ای بوده باشه.

    • تشکر شده 1

  6. نیاز دارم که برقرار بودن ارتباط به اینترنت در Build System پروژه بررسی کنم، از این رو با استفاده از تابع file یک آزمایشی می‌کنم:

    file(
         DOWNLOAD
         www.google.com
         ${CMAKE_SOURCE_DIR}/Test
         STATUS ERROR_CODE
         )

    و خروجی در متغیر ERROR_CODE به حاوی شمارهٔ کد و متن خطا به‌صورت یک لیست ذخیره می‌شود :

    نقل قول

    Store the resulting status of the operation in a variable. The status is a ; separated list of length 2. The first element is the numeric return value for the operation, and the second element is a string value for the error. A 0 numeric error means no error in the operation.

    امّا نمی‌توانم با استفاده از تابع list و ورودی GET اقدام به دریافت یک مقدار بر اساس اندیس آن می‌کنم:

    list(GET ${ERROR_CODE} 0 MESSAGE_OUT)
    message(${MESSAGE_OUT})

    امّا خروجی NOTFOUND می‌دهد، به این‌صورت نیز بررسی کرده‌ام:

    set(WITHOUT_ERROR "No error")
    
    foreach(VAR ${ERROR_CODE})
    	if(${VAR} EQUAL ${WITHOUT_ERROR})
    		message("Ghasem is here without error.")
    	endif()
    endforeach()

    امّا باز خروجی‌ای حاصل نشد.

     

    به چه صورت می‌توان این مشکل را حل کرد ؟


  7. در 3 ساعت قبل، فرهاد شیری گفته است :

    قطعا اون دوستتون در نوشتن الگوریتم های همزمانی دچار اشکال بوده!

    درود بر شما؛ یکی از دوستانی که این حرف رو هم تأیید می‌کنه آقای Anthony Williams (نویسندهٔ کتاب C++ Concurrency in Action و Maintainer کتابخانهٔ Boost.Thread) هست که در صفحهٔ ۱۲اُم به بعد از کتابشون در این مورد توضیحات لازم رو دادند که هزینهٔ استفاده از std::thread چقدر هست و فکر نمی‌کنم که دیگه ایشون در نوشتن الگوریتم چندان مشکلی داشته باشند.


  8. @zari درود بر شما؛

    برای اینکه قسمت صحیح عدد را دریافت کنید می‌تونید اون عدد double را به نوع int تبدیل کنید :

    int main (void)
    {
        double some_double = 10.23;
        float  some_float  = 32.12;
    
        printf("double %f => %d.\nfloat %f => %d.\n",
                some_double, (int) some_double,
                some_float,  (int) some_float);
    }

    خروجی:

    double 10.230000 => 10.
    float 32.119999 => 32.

     


  9. در 3 ساعت قبل، فرهاد شیری گفته است :

    دلیل بهتر بودن کد خودتون را هم بیان کنید؟

    علیکم‌السلام و درود بر شما؛ راستش با توضیحاتی که دادید خیلی گیج شدم و منتظرم که وقتی باشد تا کتابی که پیشنهاد دادید را بخوانم، چون کدهایی که دوستمان ارسال کرده‌اند درواقع برای من اصلاً جواب نداد و Segmentation Fault داده. و تا به چیزی که امروز من یادگرفته‌ام می‌دانم که آدرس یک متغیر local را نباید از تابع برگرداند و این دقیقاً کاری هست که در کد انجام شده و کاری که من کرده‌ام و دلیلی که بهتر دیده‌ام این بوده که حافظه‌ای در Heap  گرفته‌ام و آدرس آن را برگرداندم و این عمل بدون Segmentation Fault کار خود را انجام میدهد. امّا همینطوری که گفتم :

    در در 4 مهر 1398 در 11:13، قاسم رمضانی منش گفته است :
    • در کامپایلر MSVC2017 و سیستم‌عامل Windows 7 64bit کد را برای شما کامپایل و بدون مشکل اجرا می‌کند امّا خروجی درستی ندارید.
    • در کامپایلر MinGW و سیستم‌عامل Windows 7 64bit کد را کامپایل و اخطاری که در بالا اشاره کرده‌ام را داده و در هنگام اجرا برنامه با Segmentation Fault رو به رو می‌شود.
    • کامپایلرهای GCC و‌ Clang در سیستم‌عامل ArchLinux اخطار بالا را داده و همانند MinGW عمل می‌کند.
    • کامپایلر TCC در سیستم‌عامل ArchLinux نیز همانند MSVC2017 عمل می‌کند.

    اصلاً رفتار کد به درستی مشخص نبود و با توضیحات شما هم چیزی متوجه نشدم.


  10. در 2 ساعت قبل، فرهاد شیری گفته است :

    بلکه در segment .bss قرار دارد.!

    پس برای چه در خروجی اسمبلی تولید شده وجود ندارند ؟ در فیلمی که پیوند آن را ارسال کرده‌ام توضیحاتی که داده است : «توابع inline درواقع دستوراتشان در همان قسمت فراخوانی قرار گرفته و کامپایل می‌شد.» در خروجی اسمبلی دوّم درست است ما تابعی با برچسب max_int (اسم تابع ما در مثال) نداریم امّا فراخوانی آن صورت گرفته است :

    call	max_int@PLT

    و این قسمتی هست که متوجه نمی‌شم که دقیقاً چی را فراخوانی کرده ؟


  11. درود و خسته نباشید بر دوستان عزیز؛

    در New Features In C درحال بررسی قابلیّت‌های اضافه شده به استانداردهای سی بوده‌اند، درمورد توابع inline به چه صورت کامپایل می‌شود ؟ یک نمونه به این‌صورت نوشته‌ام :

    int max_int(const int i, const int j)
    { return (i > j) ? i : j; }
    
    int main (void)
    { return max_int(10, 15); }

    و خروجی اسمبلی به این‌صورت می‌باشد :

    	.file	"main.c"
    	.text
    	.globl	max_int
    	.type	max_int, @function
    max_int:
    .LFB0:
    	.cfi_startproc
    	pushq	%rbp
    	.cfi_def_cfa_offset 16
    	.cfi_offset 6, -16
    	movq	%rsp, %rbp
    	.cfi_def_cfa_register 6
    	movl	%edi, -4(%rbp)
    	movl	%esi, -8(%rbp)
    	movl	-4(%rbp), %eax
    	cmpl	%eax, -8(%rbp)
    	cmovge	-8(%rbp), %eax
    	popq	%rbp
    	.cfi_def_cfa 7, 8
    	ret
    	.cfi_endproc
    .LFE0:
    	.size	max_int, .-max_int
    	.globl	main
    	.type	main, @function
    main:
    .LFB1:
    	.cfi_startproc
    	pushq	%rbp
    	.cfi_def_cfa_offset 16
    	.cfi_offset 6, -16
    	movq	%rsp, %rbp
    	.cfi_def_cfa_register 6
    	movl	$15, %esi
    	movl	$10, %edi
    	call	max_int
    	popq	%rbp
    	.cfi_def_cfa 7, 8
    	ret
    	.cfi_endproc
    .LFE1:
    	.size	main, .-main
    	.ident	"GCC: (GNU) 9.1.0"
    	.section	.note.GNU-stack,"",@progbits

     

     

    و هنگامی که تابع را به صورت inline‌ تعریف می‌کنم:

     

    	.file	"main.c"
    	.text
    	.globl	main
    	.type	main, @function
    main:
    .LFB1:
    	.cfi_startproc
    	pushq	%rbp
    	.cfi_def_cfa_offset 16
    	.cfi_offset 6, -16
    	movq	%rsp, %rbp
    	.cfi_def_cfa_register 6
    	movl	$15, %esi
    	movl	$10, %edi
    	call	max_int@PLT
    	popq	%rbp
    	.cfi_def_cfa 7, 8
    	ret
    	.cfi_endproc
    .LFE1:
    	.size	main, .-main
    	.ident	"GCC: (GNU) 9.1.0"
    	.section	.note.GNU-stack,"",@progbits

    هر دو در اینجا max_int را فراخوانی کرده‌اند امّا در خروجی دوّم هیچ label برای max_int تعریف نشده است ! به چه صورت عمل می‌کند ؟


  12. درود بر شما؛

    در در 3 مهر 1398 در 09:20، kambiz behnia گفته است :

    1 - نوشتن به این شکل مشکل دارد یا نه؟ 

    بله مشکل دارد، همانطوری که خودتان هم گفتید دارید آدرس یک متغیر محلی را از تابع بر می‌گردانید که این اخطار را هم از سمت کامپایلر هنگام کامپایل آن تابع دریافت می‌کنید ‌:

    $ warning: function returns address of local variable

    و برنامهٔ شما هم به احتمال زیاد Segmentation Falut داده و از بین می‌رود.

     

    در در 3 مهر 1398 در 09:20، kambiz behnia گفته است :

    2 - اگر مشکلی دارد آیا نحوه استفاده ما در usedoXOR  از خروجی doXOR به عنوان ورودی strcpy موجب شده تا این مشکل خود را نشان ندهد؟

     

    در در 3 مهر 1398 در 09:20، kambiz behnia گفته است :

    3 -  آیا نوع کمپایلر و سیستم عامل میتوانند در پاسخ به دو سوال بالا تاثیرگذار باشند.

    برنامهٔ شما ممکن است که خروجی درستی نداشته باشد، چراکه دارید از یک حافظه‌ای داده را می‌خوانید که اصلاً وجود ندارد (حافظه آزاد شده است).

    • در کامپایلر MSVC2017 و سیستم‌عامل Windows 7 64bit کد را برای شما کامپایل و بدون مشکل اجرا می‌کند امّا خروجی درستی ندارید.
    • در کامپایلر MinGW و سیستم‌عامل Windows 7 64bit کد را کامپایل و اخطاری که در بالا اشاره کرده‌ام را داده و در هنگام اجرا برنامه با Segmentation Fault رو به رو می‌شود.
    • کامپایلرهای GCC و‌ Clang در سیستم‌عامل ArchLinux اخطار بالا را داده و همانند MinGW عمل می‌کند.
    • کامپایلر TCC در سیستم‌عامل ArchLinux نیز همانند MSVC2017 عمل می‌کند.

     

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

    char* doXOR(char* cData1, char* cData2)
    {
    	char* cData = malloc(256);
      	assert(cData);
    	for (int i = 0; i < 255; ++i)
    		{ cData[i] =cData1[i] ^ cData2[i]; }
    	cData[255] = '\0';
    	return cData;
    }

    و همچنین موقع استفاده :

    int main (void)
    {
    	/* ... */
    	char* tmp = doXOR(cData1, cData2);
    	strcpy(cData3, tmp);
    	printf("%s\n", cData3);
    	free(tmp); tmp = NULL;
      
    	return EXIT_SUCCESS;
    }

     

    • پسندیدن 1
    • تشکر شده 1

  13. درود بر شما، سلامت باشید؛

    برای اینکار بهتر هست که یک کلاس به عنوان Adapter درست کنید که درواقع ارتباطات شما را با این کلاس پوشش بدهد و آن کلاس را در سمت QML استفاده کنید. برای استفاده از داده‌های خودمان در سمت QML راه‌های مختلفی هست که باید مطالعه کنید و بسته به نیازتون انتخاب کنید؛ سند روش‌های برقراری ارتباط بین ++C و QML.

    یک مثال در این قسمت آقای اسدزاده زده‌اند و برای نمونهٔ اضافه بنده هم یک مثال از این روش، به‌ اینصورت‌که یک کلاس برای ارتباط برقرار کردن با کلاس QVector درست کرده‌ام :

    [پیوند فایل somewrapper.h]

    class SomeWrapper : public QObject
    {
        Q_OBJECT
        Q_PROPERTY(QString StringWrap READ readCurrentString WRITE addAnotherString)
    public:
        void addAnotherString(const QString& string)
        {
            REPORT(string, "ourStringList");
            REPORT(string, "currentString");
            this->currentString = string;
            this->ourStringList.push_back(string);
        }
        QString readCurrentString(void) const
        { return this->currentString; }
        Q_INVOKABLE QString getSomeString(const int& index) const
        { return this->ourStringList.at(index); }
    private:
        QVector<QString> ourStringList;
        QString currentString;
    };

    و به این‌صورت آن را برای موتور QML معرفی کرده‌ام :

    [پیوند فایل main.cpp]

    int main (int argc, char** argv)
    {
        QGuiApplication application(argc, argv);
        QQmlApplicationEngine qmlApplication;
    
        SomeWrapper stringBook;
        qmlApplication.rootContext()->setContextProperty
            ("StringBook", &stringBook);
        qmlApplication.load(QUrl::fromLocalFile("../../main.qml"));
        return application.exec();
    }

    و حال به راحتی می‌توانم داده‌های مورد نیاز را به سادگی از سمت QML دریافت کرده و با پردازش آن در کلاس SomeWrapper به کلاس QVector ارسال کنم :

    [پیوند فایل main.qml]

    TextField{
    	id: user_search_input
    	placeholderText: "خانهٔ مورد نظر را وارد کنید"
    	horizontalAlignment: TextInput.Center
    }
    Button{
    	text: "گَشتن"
    	onClicked: {
    		user_search_input.text =
    			StringBook.getSomeString(user_search_input.text)
    	}
    }

     

    • پسندیدن 1

  14. در در 25 شهریور 1398 در 08:47، فرهاد شیری گفته است :

    استانداردهای پایینتر هم بود

    درود؛

    درمورد نحوهٔ کار استاندارد‌ها نمی‌دانم ولی توی استاندارد توضیحی درمورد اینکه چطوری پیاده‌سازی بشه نداده، این مورد ظاهراً به‌عهدهٔ کامپایلره. مثلاً در پیاده‌سازی‌ای که GCC از N4806 کرده (فعلاً Clang هیچ پیاده‌سازی‌ای نداره) از توابع داخلی خود کامپایلر استفاده کرده :

    [آدرس فایل در مخزن گیت]

    
        // 14.1.2, source_location creation
        static constexpr source_location
        current(const char* __file = __builtin_FILE(),
    	    const char* __func = __builtin_FUNCTION(),
    	    int __line = __builtin_LINE(),
    	    int __col = 0) noexcept
        {
          source_location __loc;
          __loc._M_file = __file;
          __loc._M_func = __func;
          __loc._M_line = __line;
          __loc._M_col = __col;
          return __loc;
        }

    پیاده‌سازیه توابع داخلی (پیوند).

     


  15. درود بر دوستان عزیز؛

    وقتی در دایرکتوری‌ای که کامپوننت‌های خودمان را قرار داده‌ایم و با استفاده از فایل qmldir آن‌ها را معرفی کردیم محیط QtCreator شروع به گیج زدن می‌کند و باید حتماً کل برنامه را یک‌بار Restart کرد.

    آیا راهی برای حل این مشکل وجود دارد ؟


  16. ?تشکر بابت توضیحاتتون ممنون؛  اصرارم این بود که فکر می‌کردم اینکار ساده‌ای هست و نیازی نیست که بی‌مورد توابع libc را فراخوانی کنیم. البته به گمانم بشه کارهایی کرد ولی بهتر است که کمی اسمبلی را مطالعه کنم.


  17. با تشکر از شما، متوجه شدم که چگونه باید اشیاء را در ScrollView قرار بدم :

    ApplicationWindow {
        visible: true
        width: 640
        height: 480
        title: qsTr("Hello World")
        color: "gray"
        Rectangle{
            anchors.centerIn: parent
            width: parent.width / 2; height: parent.height / 2
            border.color: "black"
            ScrollView{
                anchors.fill: parent
                clip: true
                anchors.centerIn: parent
                Column{
                    x: 110
                    Repeater{
                        model: 40
                        Rectangle{color: "red"; border.color: "yellow"; width: 80; height: 80}
                    }
                }
            }
        }
    }

    خروجی نمونهٔ بالا :

    image.png.0cc5a62471f5c7034525d4eaec105e8d.png

    • پسندیدن 1

  18. درود بر دوستان عزیز؛

    چگونه می‌توان Itemهایی که در ScrollView قرار دارند را وسط‌چین کرد ؟:

    ApplicationWindow {
        visible: true
        width: 640
        height: 480
        title: qsTr("Hello World")
        color: "gray"
        ScrollView{
            width: parent.width / 2; height: parent.height / 2
            clip: true
            anchors.centerIn: parent
            Column{
                Repeater{
                    model: 40
                    Rectangle{color: "red"; border.color: "yellow"; width: 80; height: 80}
                }
            }
        }
    }

    در نمونهٔ بالا مثلاً می‌خواهم که تمامی Rectangleها در وسط ScrollView رندر بشوند.


  19. درود بر دوستان عزیز؛

    کامپوننت TextInput به‌صورت پیش‌فرض وقتی اشاره‌گر ماوس را روی آن می‌بریم هیچ تغییر شکلی بر روی اشاره‌گر ماوس اعمال نمی‌شود، برای حل این مشکل بنده به این‌صورت عمل کرده‌ام :

    TextInput{
        .
        .
        MouseArea{
            anchors.fill: parent
            cursorShape: Qt.IBeamCursor
        }
        .
    }

    امّا مشکلی که وجود دارد این MouseArea یک لایه بر روی TextInput‌ ایجاد می‌کند که مثلاً اگر قابلیّت selectByMouse را در TextInput فعال کرده‌باشیم دیگر کارنخواهد کرد.

    چه راه‌حلی برای این مشکل وجود دارد ؟

    • پسندیدن 1

  20. در 1 ساعت قبل، فرهاد شیری گفته است :

    در حقیقت اشاره به چهارمین عضو آرایه temp هست!

    میشه کاری کرد که اصلاً دست به اشاره‌گر string نزنه ؟ یعنی همان کد بالا ولی هیچ تغییری در محتوای اشاره‌گر string ایجاد نکنه که باعث بشه به ناکجاآباد اشاره‌کنه ؟

    در 1 ساعت قبل، فرهاد شیری گفته است :

    بلکه ایندکس شماره 0 آدرس کلی آرایه را میده!...

    بله درست متوجه شدید، و بعد چون اون اشاره‌گر از نوع کل‌آرایه هست من تبدیلش کردم به نوع *char که بتونم خونه‌های ۱ بایتی را ازش کم کنم؛ که میشه خونهٔ آخر آرایه.

    یه کم کامل‌تر بگم :

    • وقتی ما می‌نویسیم arr* یعنی مقدار خانه‌ای که arr به آن اشاره می‌کند را درخواست می‌کنیم (فرض می‌گیریم arr یک []char است).
    • حالا وقتی می‌گوییم arr& یعنی آدرس خانه‌ای که arr به آن اشاره می‌کند را می‌گیریم، با تفاوتش با arr + 2& این است که arr& آدرس کل خانه‌های arr را به ما می‌دهد  به جای آدرس یک خانه.
    • پس وقتی که arr + 1& می‌گوییم درواقع یک همچین چیزی است :
    /*
            =================
            | x | x | x | x |
            =================
                \---+---/
                    |
       char arr[]: -+
       
            =================
            | x | x | x | x |
            ======|==========
                  |
                  |
       arr + 1 : -+
      
             =================
             | x | x | x | x |
             =================
                   ^
                   |
       &arr + 1 : -+
      
         /  =================
         +> | x | x | x | x |
         \  =================
         +--------+
                  |
       &arr : ----+
      
      
            ================= -------------...
            | x | x | x | x | |  |  |  |  |...
            ================= -------------...  
                                ^
                     +----------+
                     |
       &arr + 1: ----+
    */

    و در انتها وقتی که ما نوع اشاره‌گر را به *char تغییر می‌دهیم و یک واحد کم می‌کنیم، درواقع یک واحد از نوع *char کم‌ می‌شود به جای یک واحد از نوع arr&. و اینطوری می‌توانیم به خانهٔ آخر آرایه به راحتی دسترسی داشته باشیم چرا که آن خانه در دسترس است. امّا اینکه چرا نمی‌توانم مقداری درآن خانه قرار بدم و آن رفتار کامپایلر اتفاق می‌اٌفتد عجیبه.

    در 1 ساعت قبل، فرهاد شیری گفته است :

    چه کاری این که رفتار تعریف نشده میشه!

    من فقط آدرس را می‌گیرم، اصلاً هیچ دسترسی به آن خانه ندارم که بخواد مشکلی ایجاد کنه؛ فقط آدرس را می‌گیرم و واحدهایی (به اندازهٔ مقدارحافظه‌ای که char می‌گیرد) ازش کم‌ می‌کنم که بتونم به خانهٔ آخر آرایه دسترسی داشته‌باشم، نمونه :

    #define END_OF_ARRAY(type, arr, index) \
        (*((type*) (&arr + 1) - index))
    
    int main (void){
        char string[] = "ghasem is here";
        printf("%c\n", END_OF_ARRAY(char, string, 2));
        printf("%s\n", string);
        return 0;
    }

     


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

    1.  اضافه کردن به آدرسی که به کل آرایه اشاره می‌کنه، که باعث میشه آدرس بعد از آرایه را به ما بده.
    2.  سپس type اون آدرس را به تبدیل به نوع *char می‌کنم.
    3.  و یک واحد (char) از آن آدرس کم می‌کنم که میشه خونهٔ آخر آرایه ما.

    امّا ظاهراً اون اتفاقی که می‌خواستم صورت نگرفته.

    درمورد روش‌هایی که پیشنهاد دادید :

    در 11 ساعت قبل، فرهاد شیری گفته است :

    *(((char*)&string[4])+4) = c;

     

    در 11 ساعت قبل، فرهاد شیری گفته است :

    (((char*)&string[4])[4]) = c;

    اینجا متوجه آن ۴ واحد اضافه کردن آخری نشدم، شما آدرس خانهٔ چهارم آرایه را تبدیل به *char کردید و سپس چهار واحد اضافه کردید (چرا ؟) و بعد به مقدارَش اشاره کردید.

     

×
×
  • جدید...