رفتن به مطلب
جامعه‌ی برنامه‌نویسان مُدرن ایران

فرهاد شیری

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

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

  • آخرین بازدید

  • روز های برد

    24

تمامی مطالب نوشته شده توسط فرهاد شیری

  1. با سلام همانطور که میدانید زبان سی پلاس پلاس در سالهای اخیر تغییرات شگرف و چشمگیری نسبت به سالهای اولیه پیدایش این زبان داشته است ، به طوریکه کسانی که از استاندارد های قدیمی این زبان استفاده میکنند همگی اذعان دارند که تا چند سال آینده در صورتی که از تکنیک های اضافه شده جدید به این زبان استفاده نشود و آموزش مناسبی برای این تکنیک ها دیده نشود به طور قطع به یقین نمی توان ادعا داشت که زبان سی پلاس پلاس را بلد هستیم و قادر به تولید نرم افزارهایی با قابلیت نگهداری بالاتر و مقایس پذیر تر و با قابلیت استفاده مجدد بالاتر نخواهیم بود. در صورتی که هیچ آشنایی با این سطح از تغییرات در زبان سی پلاس پلاس را ندارید، پیشنهاد میکنم مقاله دوست عزیزم جناب اسدازاده را از این لینک قابلیت‌های ممتاز ++C در نسخه‌های ۱۱ و ۱۴ و ۱۷ حتما مطالعه نمایید. در این آموزش قصد داریم که نحوه استفاده از تکنیک های جدید زبان را باهم استفاده کنیم و در صورتی که دوستان نظری راجع به این مثالها و این آموزش داشتند حتما خوشحال خواهیم شد که به ما در این مهم کمک کنید تا بتوانیم سهمی هرچند کوچک در گسترش بهتر این زبان داشته باشیم. قبلا از تمامی دوستان و اعضای محترمی که این آموزش را مطالعه میکنند و به ما کمک میکنند کمال تشکر و قدر دانی را دارم. استفاده از کلاس std::launder اشاره به آدرس یک زیر شی Sub Object در یک مجموعه، به طور مثال اگر یک struct ویک union به این صورت تعریف کنیم struct X { const int n; }; union U { X x; }; حال اگر یک شی بدین صورت تعرف کنیم... U u = {{ 1 }}; اکنون در صورتی که بخواهید از مقدار عضو n که در X تعریف شده است، توسط شی u دسترسی داشته باشیم بدون اینکه شی جدیدی از X ساخته باشیم به روش زیر عمل خواهیم کرد. X *p = new (&u.x) X {2}; اکنون اشاره گری خواهیم داشت که به یک عضو از U اشاره خواهد داشت، بنابراین نتیجه عبارت ادعایی زیر هم درست خواهد بود. assert(p->n == 2); // OK اکنون اگر عبارتی ادعایی به شکل زیر داشته باشیم قطعا یک undefined Behaviour خواهیم داشت ، بدین علت که احتمال این وجود دارد که نتوان به شی sub Object اشاره داشته باشیم. assert(u.x.n == 2); ودرنهایت در C++17 با استفاده از کلاس std::launder می توانید چنین دسترسی داشته باشید که هم ایمن هست و قطعا قابلیت استفاده مجدد بهتری هم به ارمغان خواهد آورد. assert(*std::launder(&u.x.n) == 2); // OK استفاده از کلاس std::cref , std::ref جهت دسترسی به متغیر های کلاس حافظه ای (Automatic) تعریف شده در یک تابع که به صورت Call By Reference در زمان استفاده از کلاس استاندارد std::function. به فرض مثال، تصور کنید که چند متغیر از نوع int دارید و بطور پیش فرض در زمان تعریف مقادیر اولیه ثابتی هم برای این متغییرها در نظر گرفته ایم و اکنون قصد استفاده از این متغیرها در یک تابع را داریم. اکنون اگر با استفاده از کلاس std::function یک اشاره گر به تابع بسازید و با استفاده از کلاس کمکی std::bind پارامترها مناسب را هم به تابع خود ارسال نمایید، در صورتی که در امضای تابع خود درج کرده باشید که مقادیر ورودی با ارجاع باشند، در زمان فراخوانی تابع شما به مقادیر اولیه تعریف شده در متغییرها دسترسی خواهید داشت. اکنون تصور کنید که بعد از اینکه با استفاده از کلاس std::bind پارامترها را به اشاره گر تابع مقادیر جدید برای متغیرها تعریف کرده باشید، در اینصورت اگر بازهم تابع خود را فراخوانی کنید مشاهده خواهید کرد که فقط به مقادیر اولیه در زمان تعریف متغیر ها دسترسی خواهید داشت و مقادیر جدید متغیرها در دسترس تابع قرار ندارند. اکنون برای رفع این اشکال معمولا دو اه حل وجود دارد... 1- بلافاصله بعد ازتغییر مقادیر متغیرها با استفاده از کلاس std::bind مجددا پارامترها را برای اشاره گر تابع تعریف کنید، که در اینصورت اگر 100 بار مقداردهی مختلف داشته باشید از نظر منطقی و بازدهی کار درستی هست که 100 بار از std::bind استفاده کنید؟ 2- از کلاس های std::ref برای داده های غیر ثابت و std::cref برای داده های ثابت می توانید استفاده کنید. اکنون همانطور که در مثال زیر مشاهده میکنید، در زمان تعریف متغیرهای عددی مقداری برای آنها تعریف کرده ایم و بعد با استفاده از std::bind , std::function یک اشاره گر به تابع ساخته ایم که از سه پارامتر این تابع یک پارامتر رابا استفاده از رفرنس معمولی ارسال کرده ایم و دو پارامتر را با استفاده از کلاسهای std::ref , std::cref ارسال کرده ایم، ودر مرحله بعد مقادیر متغیرها را تغییر داده ایم همانطور که انتظار داشتیم در بدنه تابع تعریف شده مقدار متغیر n با مقدارپیش فرض در دسترس خواهد بود، و قطعا تغییراتی که بر روی این متغیر لحاظ شود را نخواهد دید، نکته ای که در دوپارامتر بعدی مشاهده نمی شود. بنابراین در صورتی که نیاز به تغییر مقادیر متغیر های ارسالی به توابع را در خارج از حوزه دید تابع مورد نظر خود را دارید، و حتما هم لازم هست که تابع شما هم این تغییرات را در دسترس خود داشته باشد باید از کلاس های std::ref , std::cref استفاده نمایید. #include <functional> #include <iostream> void f(int& n1, int& n2, const int& n3) { std::cout << "In function: " << n1 << ' ' << n2 << ' ' << n3 << '\n'; ++n1; ++n2; // ++n3; } int main() { int n1 = 1, n2 = 2, n3 = 3; std::function<void()> bound_f = std::bind(f, n1, std::ref(n2), std::cref(n3)); n1 = 10; n2 = 11; n3 = 12; std::cout << "Before function: " << n1 << ' ' << n2 << ' ' << n3 << '\n'; bound_f(); std::cout << "After function: " << n1 << ' ' << n2 << ' ' << n3 << '\n' << '\n'; n1 = 13; n2 = 14; n3 = 15; std::cout << "Before function: " << n1 << ' ' << n2 << ' ' << n3 << '\n'; bound_f(); std::cout << "After function: " << n1 << ' ' << n2 << ' ' << n3 << '\n'; return 0; } این آموزش ادامه خواهد داشت....
  2. استفاده از قابلیت جدید تعریف شده در دستور using جهت ایجاد نوع داده ای جدید در C++11 به بعد... در استاندارد های قدیمی زبان برای تعریف نوع های داده ای جدید از دستور typedef استفاده میکردیم، به طور مثال فرض کنید که آرایه هایی را به این شکل تعریف میکردیم... typedef char byte; typedef int dword; typedef byte TmpDataBuf[20]; typedef byte ByteBuf[10]; typedef dword wordsBuf[15]; قطعا تصدیق میکنید که نحوه تعریف بدین شکل کمی مشکل و نگهداری برنامه را قطعا دچار مشکل خواهد کرد، لذا در استاندارد جدید تعریف شده در زبان می توانید با استفاده از دستور using را به صورت یک template تعریف نمایید.بدین ترتیب استفاده از template ها در دستورات تعریفی همچون using قابل استفاده شده و تعریف نوع واقعی به زمان اجرا انتقال داده شده است. using byte = char ; using dword = int ; template<typename T,size_t N = 15> using newDataType= T[N]; //usage newDataType<byte,20> TmpDataBuf; newDataType<byte,10> ByteBuf; newDataType<dword> wordsBuf; و قطعا تصدیق میکنید که استفاده از این نوع تعریف بسیار کاربردی تر و نگهداری کد را به مراتب بالاتری در پی خواهد داشت.
  3. فرهاد شیری

    بله می توانید در سه نخ جداگانه اجرا کنید! چون شما در حقیقت سه تا سوکت ایجاد میکنید که به یک آدرس متصل میشود پس می توانید در نخ های مختلف این عملیات را انجام دهید.! بله می توانید درنخ های مختلف اجرا کنید! منتهی حتما باید از یک قفل جهت کنترل accept استفاده کنید تا race condition رخ ندهد. بله می توانید از AcceptSock1 در دونخ مجزا استفاده کنید به شرط اینکه تمامی شرایط داده ناحیه اشتراکی را در نخ ها لحاظ کنید. در صورتی که ناحیه اشتراکی به درستی تعریف نشده باشد قطعا Race Condition و بعد هم Dead Lock رخ خواهد داد. بله میتوانید اگر شرایط ذکر کرده در بالا را رعایت کنید. بله امکان خواندن از یک سوکت هم در دونخ مجزا هم وجود دارد ولی قطعا پیچیدگی های زیادی برای داده های اشتراکی خواهید داشت. بله ولی قطعا بدون استفاده از قفل گذاری مناسب و ناحیه اشتراکی خیر! در پایان باید عرض کنم که استفاده از نخ ها در سیستم عامل ویندوز با استفاده از کلاس Thread می باشد. که البته کتابخانه های زیادی برای Concurrency , Parallel Prog وجود دارد ولی تقریبا نحوه استفاده از قفلها در ویندوز و لینوکس مشابه هستند. و در لینوکس با استفاده از کلاس pthread می توانید از نخ ها استفاده کنید. البته توجه داشته باشید که ساختمان نخ ها در هر دو سیستم عامل خیلی باهم متفاوت هستند هرچند برنامه نویس خیلی درگیر این پیچیدگی ها نیست چون خود سیستم عامل مدیریت میکنه. بنابراین برای استفاده از سوکت ها در نخ ها ویا حوضچه های نخ حتما باید قوانین نواحی اشتراکی را مد نظر قرار دهید تا هم از بازدهی هرچه بهتر پردازشگر استفاده کنید وهم برنامه ای به مراتب سریعتر از برنامه های ترتیبی ایجاد کرده باشید. ولی فکر کنم ذکر یک نکته خالی از لطف نباشد: تنها راه ایمن ماندن از خطاها و گرفتاری های نخ ها (استفاده نکردن از نخ هاست.) یعنی اگر در استفاده از نخ ها دچار افراط شوید قطعا برنامه هایی به مراتب کندتر از نسخه های ترتیبی خواهید ساخت.
  4. فرهاد شیری

    درسته که تعداد فایلهای کتابخانه دات نت خیلی زیاد هست و وابستگی ایجاد میکنه ولی توسعه یک نرم افزار تجاری (البته کشور خودمون را عرض میکنم) توسط یک شرکت نرم افزاری معتبر قطعا با دات نت ویا تکنولوژی های جاوا صورت میگیره! و در صورتی هم که حوزه نرم افزار مربوط به مسائل کلان کشور باشه قطعا لینوکس و زبان ++C,C اولین گزینه انتخاب برای توسعه خواهد بود. به همین علت به نظرم بهتره که هیجان زده نشید و نسبت به مایکروسافت یه جوری نشید
  5. فرهاد شیری

    بله می توانید تعریف کنید وقتی نوع شمارشی بدون نام در یک کلاس ویا یک استراکچر می سازید در صورتی که حوزه دسترسی این نوع شمارشی عمومی تعریف شده باشه می توانید به صورت ثابت های عضو عمومی کلاس بهشون دسترسی پیدا کنید. #ifndef TESTENUM_H #define TESTENUM_H class testEnum { public: testEnum(); virtual ~testEnum(); enum { a, b, c = 0, d = a + 2 }; enum { z, e, g = 0, f = z + 2 }; protected: private: }; #endif // TESTENUM_H testEnum t1; cout << t1.d << endl; و اگر هم برای داده شمارشی نام تعریف کنید به این صورت هم میتوانید استفاده کنید #ifndef TESTENUM_H #define TESTENUM_H class testEnum { public: testEnum(); virtual ~testEnum(); enum T1 { a, b, c = 0, d = a + 2 }; enum T2 { z, e, g = 0, f = z + 2 }; protected: private: }; #endif // TESTENUM_H testEnum t1; cout << t1.T1::a << endl; این سوال هم خیلی کلی هست ولی معمولا تعریف داده شمارشی بدون نام خیلی مرسوم نیست یا حداقل من خودم که این کار را انجام نمیدهم اونهم به این علت که نگهداری برنامه و پیچیدگی را افزایش میده وقتی روش غیر استانداردی را برای یک نوع استاندارد به کار ببریم. ولی در مجموع داده های شمارشی بر اساس ساختمانی که دارند هزینه نگهداری پایینتر و همچنین اتلاف حافظه کمتری نسبت به انواع ثابت ها را دارند.
  6. فرهاد شیری

    کدوم نارضایتی دوست عزیز! کاربرها ناراضی بودن که نمیرفتن آیفون بخرن 20 میلیون اونها مارا تحریم میکنن ما چیکار میکنیم میریم توصف خرید آیفون... شد یکبار ما اونها را تحریم کنیم و نخریم نه دوست گرامی مطمن باش حتی اگر خود گوشی را هم تحریم کنن یعنی تو جغرافیای ایران روشن نشه باز ملت میرن میخرن انقد کلنجار میرن تا بالاخره روشنش کنن یا اینکه همونطوری خاموش 15 میلیون پول میدن میخرن دیدم که میگم
  7. فرهاد شیری

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

    اگر از CLR ویا universal window platform tools در ویژوال استودیو استفاده کرده باشید قطعا برای اجرای برنامه هاتون به فریم وورک های دات نت نیاز خواهید داشت در ماشین مقصد. ولی اگر از MFC , Win32 استفاده کنید نیازی به دات نت نخواهید داشت حالا چه فایل باینری stand alone exe بسازید ویا کتابخانه های Dynamic Link Library بسازید
  9. فرهاد شیری

    به مقاله زیر مراجعه نمایید. فرق بین کامپایل استاتیک و داینامیک
  10. ادامه مقاله امنیت در نرم افزارهای تولید شده با زبان ++C به یک شی cv-qualified توسط یک شی cv-unqualified دسترسی پیدا نکنید! به برنامه زیر توجه کنید، یک روش با شرایط ثابت، که برای ذخیره سازی پنهان نتایج ناشی از دورانداختن شرایط ثابت مذکور تلاش میکند، فراخوانی میشود. به دلیل آنکه کلاس S به عنوان یک ثابت اعلام شده است. تغییر ناگهانی و جهش مقدار پنهان ذخیره شده، منجر به بروز رفتار نامشخص میگردد. #include <iostream> class S{ private: int cachedValue; int compute_value() const; // expensive public: S() : cachedValue(0) {} int get_value() const{ if (!cachedValue){ const_cast<S *>(this)->cachedValue = compute_value(); } return cachedValue; } }; void f(){ const S s; std::cout << s.get_value() << std::endl; } اکنون برای رفع این مشکل کافی است که نوع متغیر عضو کلاس را به صورت mutable تعریف نماییم. #include <iostream> class S{ private: mutable int cachedValue; int compute_value() const; // expensive public: S() : cachedValue(0) {} int get_value() const{ if (!cachedValue){ cachedValue = compute_value(); } return cachedValue; } }; void f(){ const S s; std::cout << s.get_value() << std::endl; } نباید یک شی لاندا بیشتر از اشیایی رجوع شده به خود، عمر کند! این امکان وجود دارد که عبارت لاندا، اشیای دارای مدت زمان ذخیره سازی خودکاری را از مجموعههای ازحوزه های پیوسته حوزه ی دسترسی، برای استفاده در بدنه ی تابع، رصد و دریافت کند. ممکن است این رصد به صورت صریح و از طریق مشخص کردن شی در capture-list لاندا، یا به صورت ضمنی و با استفاده از capture-default و ارجاع به شی در بدنه ی تابع لاندا صورت پذیرد. هنگامی که یک شی به وسیله ی کپی رصد میشود، شی لاندا شاملیک عضو داده ای غیرایستای بدون نام خواهد شد، که مقدار اولیه برابر با مقدار شی مورد رصد است. طولعمر عضو داده ای غیرایستا نیز برابر با طول عمر شی لاندا خواهد بود. با این وجود، هنگامیکه یک شیتوسط مرجع رصد می شود، طول عمر مورد ارجاع به طول عمر شی لاندا گره نخورده است. بنابراین هنگامیکه یک شی لاندا از شی مورد ارجاع و رصد خود بیشتر عمر کند، مادامیکه شی مورد ارجاع و رصد در دسترس است، اجرای عملگر فراخوانی تابع شی لاندا منجر به بروز رفتار نامشخص میشود.بنابراین، شی لاندا نباید طول عمری بیشتر از شی مورد ارجاع و رصد خود داشته باشد. به مثال زیر توجه نمایید، یک مرجع لاندا، یک متغیر محلی را از یک لاندای بیرونی رصد میکند. با این وجود، طولعمر این لاندای داخلی بیشتر از لاندای بیرونی و متغیرهای محلی خودکار تعریف شده ی آن است. هنگامیکه شی لاندای داخلی در ()f اجرا میشود، رفتار نامشخصی روی خواهد داد. auto g(int val){ auto outer = [val]{ int i = val; auto inner = [&]{ i += 30; return i; }; return inner; }; return outer(); } void f(){ auto fn = g(12); int j = fn(); } برای رفع این اشکال کافی است که لاندای inner متغیر i را نه از طریق ارجاع بلکه از طریق کپی رصد نماید. auto g(int val){ auto outer = [val]{ int i = val; //auto inner = [=] () mutable { //OR auto inner = [i]{ i += 30; return i; }; return inner; }; return outer(); } void f(){ auto fn = g(12); int j = fn(); } زمانی که عملگر new را سربارگذاری میکنید حتما باید عملگر delete را هم سربارگذاری نمایید به برنامه زیر توجه نمایید، #include <Windows.h> #include <new> void *operator new(std::size_t size) noexcept(false){ // Private, expandable heap. static HANDLE h = ::HeapCreate(0, 0, 0); if (h){ return ::HeapAlloc(h, 0, size); } throw std::bad_alloc(); } // No corresponding global delete operator defined. در صورتی که هیچ کلاس کمکی برای سربار گذاری در نظر نگرفته باشید قطعا نمی توانید از عملگر delete بر روی حافظه رزرو شده توسط این تابع استفاده کنید. بنابراین بهتره از یک کلاس پوشاننده استفاده کنیم.. #include <Windows.h> #include <new> class HeapAllocator{ private: static HANDLE h; static bool init; public: static void *alloc(std::size_t size) noexcept(false){ if(!init){ h = ::HeapCreate(0, 0, 0); // Private, expandable heap. init = true; } if(h){ return ::HeapAlloc(h, 0, size); } throw std::bad_alloc(); } static void dealloc(void *ptr) noexcept{ if (h){ (void)::HeapFree(h, 0, ptr); } } }; HANDLE HeapAllocator::h = nullptr; bool HeapAllocator::init = false; void *operator new(std::size_t size) noexcept(false){ return HeapAllocator::alloc(size); } void operator delete(void *ptr) noexcept{ return HeapAllocator::dealloc(ptr); }
  11. با توجه به اهمیت امنیت نرم افزار، شرکت های بزرگ دنیا به ارائه راهکارهایی چون طراحی زبان ها و محیط های برنامه نویسی و مفسر و مترجم هایی با قابلیت های کنترل امنیتی بر روی سیستم عامل و بسیاری از راهکارهای دیگر پرداخته اند اما با توجه به عدم توانایی راهکارها در کنترل تمامی موارد امنیتی، عدم امکان پیاده سازی راهکارهای امنیتی بر روی برخی ساختارها، ایجاد محدودیت برای دسترسی به برخی منابع و امکانات و مشکلات کوچک و بزرگ دیگر برنامه نویسی یک برنامه به صورت ایمن بهترین راهکار برای محافظت از یک برنامه است. یکی از زبان هایی که در کنار محبوبیت در میان برنامه نویسان، همیشه یکی از زبان های پر بحث در برنامه نویسی ایمن بوده است، خانواده زبان های C به خصوص ++C است. در این زبان ها عمده مدیریت منابع به برنامه نویس واگذار شده که در صورت عدم مدیریت درست آن ها، آسیب پذیری های مختلفی رخ می دهد. بهترین راهکار برای جلوگیری از بروز آسیب پذیری نرم افزارها، برنامه نویسی پدافندی و ایمن آن نرم افزار از ابتداست. دراین مستندات، باتوجه به جامعیت و کاربرد فراوان زبان ++C درکنار محبوبیت، مباحث ونکات اساسی در برنامه نویسی پدافندی و ایمن این زبان مطرح شده و انواع آسیب پذیری و شیوه جلوگیری از بروز آن ها و رفع آن ها در صورت بروز، توضیح داده می شود. همچنین سعی می شود تا راهکارهای ارائه شده تا حد امکان قابل پیاده سازی در زبان C نیز باشند. با توجه به گستردگی ابزارهای برنامه نویسی این زبان و وجود کامپایلرهای مختلف، زبان معیاری برای این مستند مدنظر قرار گرفته شده است و ساختار ارائه شده مربوط به ابزار یا کامپایلر خاصی نیست اما بنا بر نیاز مثال هایی در کنار زبان معیار از ابزارهایی خاص نیز ارائه می گردد. رفتار تعریف نشده ممکن است شامل مختل شدن عملکرد برنامه(Crash) خروجی نامربوط و غلط، بروز آسیب پذیری های نرم افزاری و موارد دیگر می باشد. وجود رفتار نامتعارف در یک برنامه نه تنها امنیت خود آن برنامه ، بلکه ممکن است امنیت سیستم عامل، شبکه را نیز به خظر بیندازد. جلوگیری از بروز رفتارهای تعریف نشده و مقابله با آن ها از مباحث مهم برنامه نویسی تدافعی و ایمن است. توابع بدون آرگومان برای تعریف یک تابع بدون آرگومان باید از کلمه کلیدی void در زمان تعریف تابع استفاده نمایید.با این کار تزریق کد توسط هکرها را مختل می کنید. int getValue(void) { return 1; } اعداد تصادفی در صورت نیاز به اعداد تصادفی از تابع ()rand استفاده نکنید به این علت که خروجی این تابع در تکرارهای بالا دچار تکرار می شود. بهتراست از تابع ()srand استفاده کنید می توانید برای آن seed تعریف کنید تا احتمال تکرار را به حداقل برسانید. در ویندوز هم می توانید از تابع ()CryptGenRandom استفاده کنید و در لینوکس هم تابع ()random و تابع ()srandom استفاده نمایید. #include <windows.h> #include <wincrypt.h> #include <iostream> int main(void) { HCRYPTPROV hcp; CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, 0); long int li = 0; CryptGenRandom(hcp, sizeof(li), (BYTE *)&li); printf("Random number is -> %ld\n", li); return 0; } عدم استفاده از تابع بازگشتی جهت مقدار دهی اولیه به آرایه ای با کلاس حافظه استاتیک در مثال زیر زمان ساخته شدن و مقدار دهی اولیه آرایه cache تابع fact مجددا فراخوانی شده واین عمل به دلیل ایستا بودن آرایه باعث بروز رفتار تعریف نشده و خطا خواهد شد. #include <stdexcept> int fact(int i) noexcept(false) { if (i < 0) { throw std::domain_error("i must be >=0"); } static const int cache[] = { fact (0), fact(1), fact(2), fact(3), fact(4), fact (5), fact (6), fact(7), fact(8), fact(9), fact(10), fact (11), fact (12), fact(13), fact(14), fact(15), fact(16) }; if (i < (sizeof(cache) / sizeof(int))) { return cache[i]; } return i > 0 ? i * fact (i - 1) : 1; } حال برای رفع این اشکال طبق نمونه کد زیر آرایه را بدون استفاده initializer list با استفاده از یک متغیر ثابت که تعداد عضو های آرایه را معین میکند تعریف شده است و ازآنجا که کامپایلر آرایه های از جنس کلاس حافظه استاتیک را خود با عدد 0 مقداردهی میکند دیگر یک آرایه از قبل پر شده نخواهیم داشت و در مرحله با استفاده از تکنیک lazy به هر یک از عضوهای آرایه مقدار مناسب را با استفاده از تابع بازگشتی مقدار دهی خواهیم کرد. #include <stdexcept> const int arraySize = 17 int fact(int i) noexcept(false) { if (i < 0) { throw std::domain_error("i must be >=0"); } static int cache[arraySize]; if (i < (sizeof(cache) / sizeof(int))) { if (0 == cache[i]) { cache[i] = i > 0 ? i * fact(i - 1) : 1; } return cache[i]; } return i > 0 ? i * fact(i - 1) : 1; } الحاق مضاعف هدر فایل ها الحاق مضاعف زمانی رخ می دهد که یک هدر دو ویا چند بار به برنامه اضافه شوند. در مثال زیر در کلاس c هدرهای a , b الحاق می شوند در حالی که در کلاس b هم هدر a الحاق شده است که الحاق مضاعف رخ داده است. //a.h struct a { int membe }; //b.h #include "a.h" //c.c #include "a.h" #include "b.h" برای جلوگیری از این الحاق های مضاعف می توانید از روش زیر استفاده نمایید //a.h #ifdef A_H #define A_H struct a { int member; }; #endif ویا می توانید از دستور pragma استفاده کنید البته این دستور جز دستورات استاندارد ++c / c نمی باشد ولی اکثر کامپایلرها این دستور را اجرا میکنند. //a.h #pragma once struct a { int member; }; رمزنگاری اصولی جهت رمزنگاری داده های حساس در برنامه های خود می توانید از کتابخانه ++Crypto وهمچنین کتابخانه libcrypto از OpenSSL نیز استفاده نمایید. رمز نگاری به چند دسته اصلی تقسیم می شود: 1- رمزنگاری درهم سازHash که میتوان به الگوریتم های MD6 , MD5 , SHA-1,SHA-0 اشاره کرد. 2- رمزنگاری با کلید متقارن که می توان به الگوریتم های RC4 , AES , DES , 3DES اشاره کرد. 3- رمزنگاری با کلید عمومی نا متقارن که می توان به الگوریتم های RSA , DSA , DSS اشاره کرد. 4- کد گذاری دودویی به متن که می توان به الگوریتم های Base32 , Base58 , Base64 ,Base85 اشاره کرد. مدیریت مقدار و نوع داده ها و مقدار دهی اولیه در مثال زیر متغیر هایی تعریف شده اند که مقدار اولیه ندارند (البته درست است که در برخی از کامپایلرها این متغیرها را مقدار دهی خواهند کرد، ولی توجه داشته باشید که تکنیک های برنامه نویسی تدافعی جدای از امکانات کامپایلر می باشد) int main (void) { int a; float b; char c; bool d; return 0; } اکنون مشاهده میکنید که بعد از اجرای برنامه چه مقدار هایی در متغیرها ذخیره شده است. پس بنابراین مقدار دهی اولیه متغیرها یا باید برحسب نیاز در همان ابتدا تعریف صورت گیرد یا در صورت عدم نیاز به وجود مقدار اولیه خاص، مقدار دهی با استفاده از تابع همان نوع داده انجام خواهد شد. int main (void) { int a = int(); float b = float(); char c = char(); bool d = bool(); return 0; } و بعد از اجرا به این صورت خواهد بود مقدار دهی اولیه به آرایه ها int main (void) { int a[5]; float b[5]; char c[5]; bool d[5]; return 0; } که بعد از اجرا بدین صورت خواهد بود... و برای رفع این اشکال باید همیشه آرایه ها را مقدار دهی اولیه نمایید. int main (void) { int a[5] = {}; float b[5] = {}; char c[5] = {}; bool d[5] = {}; return 0; } وبعد از مقدار دهی اولیه به آرایه ها خواهیم داشت ... ادامه خواهد داشت این مقاله...
  12. فرهاد شیری

    یک سر به لینک زیر بزنید Using ActiveX controls and COM in Qt
  13. سلام به نظرم در این برهه از زمان تسلط در یک زبان ویا یک Frame Work به هیچ وجه نمیتونه تضمینی برای آینده یک مهندس نرم افزار ویا یک برنامه نویس باشه! بنابراین بهتره سعی کنید ++C را شروع کنید و بصورت موازی Frame Work Qt را هم استفاده کنید، ولی به هیچ وجه از تکنولوژی های سمت زبان جاوا غافل نشید. صرف تسلط به زبان ++C الان نمیتونه خیلی مهم باشه، (البته شرایط تجاری بازار IT کشور خودمون را عرض میکنم) اونهم به این علت که قطعا درصد بسیار کمی از شرکتهای معتبر که الان در ایران فعال هستند، زبان ++C را به عنوان تکنولوژی توسعه ای نرم افزارها شون انتخاب میکنن که اونهم بخاطر خیلی از دلایل که قبلا بارها بحث شده. که البته شانس استخدام در این شرکتها هم خیلی پایین هست. متاسفانه مشکل هم از اونجا شروع میشه که، کسانی که بدون فکر و منطق هجوم میارن سمت زبانهایی مثل سی پلاس پلاس فکر میکنن با خوندن دوتا کتاب و دوتا پروژه روی گیت ایجاد کردن و مطالعه سایتهای رفرنس می تونن در زبان سی پلاس پلاس تجربه کسب کنند که قطعا نمیتونه اینطور باشه! هرچند نام کیوت و سی پلاس پلاس خیلی بزرگ جلوه میکند اما واقعیت چیزه دیگه ای هست. پس تا وقتی هم که شما شرایط قرار گرفتن دریک تیم توسعه ای نرم افزاری که تکنولوژی توسعه ی نرم افزارهای تجاری شون با زبان سی پلاس پلاس ویا فریم وورک کیوت هست، را نداشته باشید قطعا نمیتونید دراین زمینه به یک دانش خوب و قوی دست پیدا کنید. به همین علت اگر برنامه نویسی که بخواد در این بازار مشغول باشه بهتره حتما از تکنولوژی های دات نت و جاوا و تکنولوژی های سمت وب اطلاعات کافی داشته باشه.
  14. فرهاد شیری

    احسنت! دست مریضاد...
  15. فرهاد شیری

    یک سوال نسبتا پیچیده! مربوط به معماری کامپیوتر در مقطع ارشد برخوردم، من راه حلی که به ذهنم می رسید را نوشتم. دوستان اگر کسی علاقه داشت و راه حل دیگه ای داره ویا حتی اگر راه حل من صحیح نیست خوشحال می شوم، بیان کنید. سوال: برنامه زیر را در نظر بگیرید. A یک آرایه با آدرس شروع 0 است. اگر یک Data Cache با دسترسی Direct Mapping با گنجایش 4 کلمه در اختیار داشته باشیم، Hit Rate را محاسبه نمایید؟ فرضیات: متغیر های i , j , t در ثباتهای پردازشگر ذخیره شده اند. محتویات خانه های حافظه در ثباتهای SS,SP ذخیره نمی شوند، یعنی به ازای هر بار فراخوانی آرایه A یکبار به حافظه Cache دسترسی خواهیم داشت. فرض کنید آرایه به صورت صعودی مرتب شده است. For (int I = 0 ; i < 5 ; i++) For (int j = i ; j < 5 ; i++) If ( A[i] < A[j] ) { T=A[i]; A[i] = A[j]; A[j] = t; }
  16. فرهاد شیری

    جوابم را سعی کردم بهتر نشون بدم! دوستان اگر نظری داشتید بنده را بی نصیب نذارید! بنابراین می توان نتیجه گرفت در صورتی که آرایه A int A[]{1,2,3,4,5}; با این مقادیر در حافظه وجود داشته باشد، استنباط این است در اولین آدرس دهی Cache وبا هربار فراخوانی Cache مقادیر 1 و 3 و 5 با نرخ Hit 100 وجود خواهند داشت. و مقادیر 2 و 4 در Cache در دسترس نخواهند بود ومجددا آدرسی دهی خواهد شد.
  17. فرهاد شیری

    سپاسگذار زحمات شما هستم
  18. فرهاد شیری

    عالی مثل همیشه!
  19. فرهاد شیری

    جناب اسدازاده! تشکر از مقاله ها و اشتراک گذاری دانش فنی خودتون در اختیار افرادی امثال من، قدردان زحمات شما هستیم!
  20. فرهاد شیری

    تشکر! و سپاس فراوان
  21. فرهاد شیری

    عالی! مثل همیشه
  22. فرهاد شیری

    عالی! سپاسگذار زحمات شما هستیم
  23. فرهاد شیری

    تشکر مثل همیشه عالی! موفق باشید!
  24. فرهاد شیری

    سرکار خانم انصاری! از زحمات شما در ارائه این مقالات فنی و پربار کمال تشکر دارم. البته بر اساس تجربه 18 ساله در دنیای نرم افزاری که دارم عرض کردم. با سپاس
  25. با سلام! در این تاپیک قصد دارم هرچه ساده ابزارهایی که معمولا برنامه نویسان حرفه ای جهت طراحی بهتر و بهینه تر نرم افزارهای خود از آنها بهره می برند را معرفی کنم! خواهشمندم دوستان اگر کسی نرم افزاری که توسط خودش استفاده میشه! و در راستای این تاپیک هست لطفا همکاری کنید! با تشکر! فقط دوستان خواهشا کپی نباشه از جای دیگه! اگر نرم افزاری که خودتون استفاده میکنید معرفی کنید!
×