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

پرچمداران

  1. کامبیز اسدزاده

    کامبیز اسدزاده

    بنیـــان گذار


    • امتیاز

      154

    • تعداد ارسال ها

      368


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

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

    مدیران مرجع


    • امتیاز

      36

    • تعداد ارسال ها

      89


  3. سید محمد عباسی

    سید محمد عباسی

    کاربـــر رسمی


    • امتیاز

      15

    • تعداد ارسال ها

      35


  4. بهنام صباغی

    بهنام صباغی

    مدیران مرجع


    • امتیاز

      14

    • تعداد ارسال ها

      82



مطالب محبوب

در حال نمایش مطالب دارای بیشترین امتیاز از زمان شنبه, 6 بهمن 1397 در همه بخش ها

  1. 6 امتیاز
    مراحل ساخت برنامه‌ در زبان سی‌پلاس‌پلاس پیش نویس ۰.۶ قبل از هر چیز به اینفوگرافی زیر توجه کنید که مراحل ساخت برنامه در سی‌پلاس‌پلاس را نشان می‌دهد. مقدمه‌ای بر همگردانی (کامپایل) و اتصال (لینک کردن) این سند مرور مختصری در رابطه با مراحل را برای شما فراهم می‌کند تا به شما در درک دستورات مختلف برای تبدیل و اجرای برنامه‌ی خودتان کمک کند. تبدیل مجموعه‌ای از فایل‌های منبع و هدر در سی‌پلاس‌پلاس به یک فایل خروجی و اجرایی در چندین گام (به طور معمول در چهار گام) پیش‌پردازنده (Preprocessors)، کامپایل و گرد‌آوری (Compilation)، اسمبلر (Assmbler) و پیوند دهنده (Linker) تقسیم می‌شود. قبل از هر چیز اگر در محیط توسعه‌ی Qt Creator داخل فایل .pro مقدار زیر را وارد کنید، تا بتوانید فایل‌های ساخته شده‌ی موقت در زمان کامپایل را مشاهده کنید. QMAKE_CXXFLAGS += -save-temps این دستور اجازه‌ی آن را خواهد داد تا فایل‌هایی با پسوند .ii و .s در شاخه‌ی بیلد پروژه تولید شوند که در ادامه به آن‌ها اشاره شده است. تعریف پیش‌پردازنده پیش‌پردازنده‌ها (Preprocessors) درواقع دستوراتی هستند که اجازه می‌دهند تا کامپایلر قبل از آغاز کردن مراحل کامپایل دستوراتی را دریافت کند. پیش‌پردازنده‌ها توسط هشتگ (#) مشخص می‌شوند این نماد در سی‌++ مشخص میکند که دستور فوق از نوع پیش‌پردازنده می‌باشد که نتیجه‌ی آن در قالب ماکرو (Macro) در دسترس خواهد بود. برای مثال ماکروی __DATE__ توسط پیش‌پردازنده‌ها از قبل تعریف شده است که مقدار تاریخ و زمان را بازگشت می‌دهد. بنابراین هرکجا که از آن استفاده شود کامپایلر آن را جایگزین متن خواهد کرد. در شکل زیر مرحله‌ای که از پیش‌پردازنده‌ها استفاده می‌شود آمده است: پیش‌پردازنده، کامپایل (گردآوری کردن)، لینک (پیوند کردن) و ساخت برنامه اجرایی فرایند تبدیل مجموعه‌ای از فایل‌های متنی هِدر و سورس سی‌++ را «ساخت» یا همان Building می‌گویند. از آنجایی که ممکن است کُد پروژه در بسیاری از فایل‌ها هدر و سورس سی++ توسعه و گسترش یابدمراحل ساخت در چند گام کوچک صورت می‌گیرد. یکی از رایج‌ترین موارد در مراحل گردآوری (ترجمه‌ی یک کد سی‌پلاس‌پلاس به دستورالعمل‌های قابل فهم ماشین) است. اما گام‌های دیگری نیز وجود دارد، پیش‌پردازنده و لینک (پیوند‌ها) این بخش به طور خلاصه توضیح می‌دهد که چه اتفاقی در هر یک از مراحل رُخ می‌دهد. یک کامپایلر یک برنامه‌ی خاص است که پردازش اظهارات (دستورات) نوشته شده در یک زبان برنامه‌نویسی خاص را به یک زبان ماشین که قابل فهم برای پردازنده می‌باشد تبدیل کند. به طور معمول یک برنامه‌نویس با استفاده از یک ویرایشگر که به محیط توسعه‌ی یکپارچه‌ی نرم‌افزار (IDE) مشهور است توسط زبان برنامه‌نویسی مانند ++C دستورات (اظهارات) را می‌نویسد. فایل ایجاد شده با نام (filename.cpp در زبان برنامه‌نویسی سی‌پلاس‌پلاس) شامل محتوایی است که معمولاً به عنوان دستورات برنامه‌نویسی سطح بالا نامیده می‌شود. سپس برنامه‌نویس کامپایلرِ مناسب برای زبان برنامه‌نویسی مانند سی++ را اجرا می‌کند و نام فایل‌هایی که حاوی دستورات هستند را برای کامپایل مشخص می‌کند که این انتخاب و مشخص سازی توسط IDE به راحتی قابل مدیریت است. پس از آن، کار کامپایلر این است که فایل‌های منبع .cpp را جمع آوری کرده و پیش‌پردازنده‌ها را بررسی کند تا دستورات احتمالی را اجرا نماید که نتیجه‌ی این مرحله در فایلی با پسوند .ii ر قالب filename.ii تولید می‌شود که در این فرایند نیز خط به خط کُد‌های موجود در آن‌ها را بررسی می‌کند تا خطاهای احتمالی نحو (سینتکس - Syntax) بررسی می‌شود و آن‌ها را به طور ترتیبی به دستورالعمل‌های سطح ماشین تبدیل کند. توجه داشته باشید که هر نوع پردازنده‌ی کامپیوتر دارای مجموعه‌ای از دستورالعمل‌هایِ ماشین خودش است. بنابراین کامپایلر تنها برای سی++ نیست، بلکه برای اهداف و مقاصد خاص هر پلتفرم است. پس کد‌هایی که توسط پیش‌پردازنده سی‌پلاس‌پلاس به زبان اسمبلی برای معماری مورد نظر در پلتفرم مقصدترجمه شده‌اند نتایج آن در فایلی با پسوند .ss در قالب filename.ss قابل نمایش هستند که در حالت عادی قابل رویت نیست. توجه داشته باشید که باید در این مرحله باید مشخص شود برنامه قرار است توسط چه نوع پردازنده‌ای تحتِ چه نوع معماری مونتاژ (اسمبل) شود. برای مثال پردازنده‌ها با انواع معماری‌های مختلف وجود دارند که برخی از آن‌ها به صورت x86-x64، x64، ARMv7، aarch64 غیره ... می‌باشند. شکل یک (کامپایل یک فایل منبع ++C) مرحله‌ی سوم را در نظر داشته باشید که عمل کامپایل فایل سی‌پلاس‌پلاس در دو مرحله قبلی یک فایل اجرایی را تولید نمی‌کند. برنامه‌ای که توصیف شده است، احتمالاً توابعی را در رابط‌های برنامه‌نویسی (API) و یا توابع ریاضی یا توابع مرتبط با I/O را فراخوانی کند که ممکن است شامل فایل‌های هدر مانند iostream یا fstream و حتی ماژول‌های دیگری که در زبان‌ تعبیه شده‌اند را داشته باشد که فایل تولید شده توسط کامپایلر در این مرحله یک فایل شیء نامیده می‌شود که با پسوند .o به صورت filename.o تولید خواهد شد که علاوه بر دستورالعمل‌های تبدیل شده به کد ماشین، شامل توابع و دستورالعمل‌های خارجی نیز می‌باشد. هرچند در این مرحله دستورات تبدیل به دستورالعمل‌های قابل فهم توسط پردازنده شده‌اند اما فعلاً قابل اجرا نیستند چرا که باید این توابع خارجی افزوده شده را به آن لینک کرد که در مرحله‌ی بعد یعنی مرحله‌ی چهارم اتفاق می‌افتد. در نهایت مرحله‌ی چهارم فایل با پسوند .o که شامل کد‌های تولید شده توسط کامپایلر به زبان ماشین است که پردازنده‌ها می‌توانند این دستورات را درک کنند که همراه با کد‌های تولید شده‌ی هر کتابخانه‌ی دیگری که مورد نیاز است توسط لینکر (لینک شده) و در نهایت جهت تولید یک فایل اجرایی مورد استفاده قرار می‌گیرند که نوع آن فایل از نوع اجرایی یا در واقع Executable File خواهد بود. شرح کامل فرایند ساخت فایل اجرایی اکثر پروژه‌ها دارای مجموعه‌ای از فایل‌های هدر سی++ هستند، که امکان ماژولار شدن در آن را فراهم می‌کند و مجموعه‌ای از آن می‌تواند به عنوان بخش‌های کوچکی از برنامه محسوب شوند. برای ساخت چنین پروژه‌هایی هر فایل سی‌پلاس‌پلاس باید کامپایل شود و سپس فایل‌های ساخته شده در قالب شیء (آبجکت) باید همراه توابع و کتابخانه‌های دیگر لینک (پیوند) شوند. البته هر گام از مراحل کامپایل شامل یک مرحله پیش‌پردازنده است که دستورالعمل # عمل تغییرات و اصلاحیه‌ها را در فایل متن اعمال می‌کند. شکل زیر فرایند ساخت چند فایل به صورت همزمان را نشان می‌دهد:
  2. 4 امتیاز
    فایل‌ها/تغییرات پروژه را چطوری کنترل کنیم ؟ در وهلهٔ اوّل شاید بگید چه نیازیه ؟ خب برنامه رو می‌نویسیم و میریم دیگه !. درسته برنامه‌اتون را می‌نویسید و می‌روید؛ امّا به کجا چنین شتابان ؟ آیا همیشه برنامهٔ شما کوچک‌خواهد بود ؟ آیا قراره برنامهٔ شما در صد خط تمام بشه ؟ یا اینکه کلاً قصد توسعه‌اش رو دیگه ندارید ؟ خب شاید یکی دیگه داشت :). فرض کنید برنامهٔ‌تان را نوشتید : void parsing(int argc, char **argv){ top = 0; for (unsigned i=1; i < (unsigned)argc; i+=2){ listArgs[top].name = argv[i]; listArgs[top].value = argv[i+1]; top++; } } خب، برنامه‌کار می‌کنه و میرید و یک هفته‌ٔ دیگه میاید و مثلاً خط : top = 0; را حذف می‌کنید. و برنامه در اجرای اوّل درست کار می‌کنه؛ پیش‌خودتون می‌گید خب چه نیازی بود، الکی ماهم کد نوشتیم :). امّا بعداً در اجراهای متوالی برنامه شروع می‌کنه به دادن خروجی‌های نامتعارف. اینجاس که باید ساعت‌ها وقت بزارید و بگردید ببینید آخرین‌بار چه چیزی رو تغییر دادید و کدوم فایل را ویرایش کردید. کار مسخره‌ و اعصاب‌خورد کنی میشه، درسته ؟. امّا برای مدیریت این دَنگٌ‌وفَنگ‌ها می‌تونید از سیستم‌های‌مدیریتپروژه‌ استفاده بکنید. مثل Git حالا اینکه چرا گیت ؟ به خاطر اینکه راحت‌ترینه و بهترینه. چرا ؟ چون امتحانش را پس داده، پروژهٔ بزرگ "کرنل‌لینوکس" را داره مدیریت می‌کنه. حالا بیاید ببینیم اگه ما ازت گیت (git) استفاده می‌کردیم، چطوری می‌توانستیم بفهمیم که چه بلایی سر کد آمده : ۱- اوّل گزارشات را چک می‌کنم، تا ببینم آخرین گزارشی که از تغییرات ذخیره کردم چه بوده ؟: $> git log commit bb513a5f9ec429222de03afa690e7fa5d2fbdf6e (HEAD -> master) Author: Ghasem Ramezani <g1999ramezani@gmail.com> Date: Sun May 5 00:05:22 2019 +0430 create a bug commit ab176fa8a282a74e6badfc285c0986bc66ee6b7d (origin/master, origin/HEAD) Author: Ghasem Ramezani <g1999ramezani@gmail.com> Date: Sat May 4 10:40:32 2019 +0430 make `top` to be 0 at first of parsing() function and make class storage of listArgs to be `extern` and getOption() function return "NULL" on Failure. خب فهمیدم که آخرین تغییرم با عنوان create a bug ثبت شده، حالا باید از شناسه‌اش استفاده کنم. ۲- تغییراتی که در آن گزارش ثبت شده است را مشاهده می‌کنم. : $> git show bb513a5f9ec429222de03afa690e7fa5d2fbdf6e commit bb513a5f9ec429222de03afa690e7fa5d2fbdf6e (HEAD -> master) Author: Ghasem Ramezani <g1999ramezani@gmail.com> Date: Sun May 5 00:05:22 2019 +0430 create a bug diff --git a/source/arg.c b/source/arg.c index c776ff2..a75c91d 100644 --- a/source/arg.c +++ b/source/arg.c @@ -7,7 +7,6 @@ unsigned top=0; struct ARGS listArgs[MAX_ARG]; void parsing(int argc, char **argv){ - top = 0; for (unsigned i=1; i < (unsigned)argc; i+=2){ listArgs[top].name = argv[i]; listArgs[top].value = argv[i+1]; دیدی به چه سادگی توانستیم تغییری که دادیم را پیدا کنیم ؟ البته این انتهای ماجرا نیست ! الآن که متوجه شدیم در کدام گزارش‌ما خراب‌کاری کردیم؛ کافیه که تغییرات را به گزارش قبل از خراب‌کاری برگردانیم : $> git reset --hard ab176fa8a282a74e6badfc285c0986bc66ee6b7d البته قابل ذکره که ما اینجا تنها داخل این گزارش فقط یک تغییر داشتیم، مسلماً کار می‌تونه کمی پیچیده‌تر بشه اگه تغییرات زیاد باشن، که همیشه هستن . چگونه با گیت (git) کار کنیم ؟ بسیار ساده، مسلماً اوّل نیاز دارید که این برنامه را نصب کنید. این برنامه به طور پیش‌فرض در سیستم‌عاملتون نصب نیست. کافیه که از مدیربستهٔ سیستم‌عاملتون کمک بگیرید، مثلاً برای Debian - Ubuntu - Ubuntu Mint به این‌صورت کار تمام می‌شود : $ apt install git حالا بعد از نصب، نیاز دارید که مشخصاتتان را ثبت کنید، دقت کنید که تمام توضیحاتی که بنده می‌دهم را می‌توانید به‌صورت کامل‌تر از سایت گیت (git) دنبال کنید. $> git config --global user.name "Ghasem Ramezani" $> git config --global user.email "g1999ramezani@gmail.com" $> git config --global core.editor emacs دو مورد اوّل که واضح هستن، امّا مورد آخر دل‌بخواه خودتان هست، زمانی‌که نیاز باشه گیت (git) ویرایشگرمتنی را جهت ویرایش‌باز بکند باید بداند که کدام ویرایشگر مورد علاقهٔ شماست. می‌توانید هر برنامه‌ای را قرار بدهید. امّا دقت کنید که بهترین ویرایشگر‌ها می‌توانند Vim, Emacs, Notepad++ باشند؛ فایل این تنظیمات را می‌توانید از این مسیرها دنبال کنید : User Space : ~/.gitconfig System Wide: /etc/gitconfig ساخت مخازن (repository) خب حالا که نصب/پیکربندی انجام شد، کافیه که مخزن (repository) خودمان را راه‌اندازی کنیم. یک پروژهٔ جدید درست کنید و گیت (git) را مقداردهی (Initialize) کنید : $> mkdir project ; cd project $> git init ما یک دایرکتوری به اسم project درست کردیم، و مخزن (repository) خودمان را با دستور git init راه‌اندازی کردیم، یک سری فایل‌هایی گیت (git) برای ما داخل آن دایرکتوری با اسم .git درست کرده. تغییراتی‌که نیاز رو انجام میدیم، مثلاً در وهلهٔ اوّل دایرکتوری‌ها و فایل‌های پروژه را راه‌اندازی می‌کنیم : $> mkdir header source build object $> touch header/arg.h source/arg.c Makefile $> tree . ├── build ├── Makefile ├── header │ └── arg.c ├── object └── source └── arg.h 4 directories, 3 files $> اگه درمورد Makefile نمی‌دانید، می‌توانید از اینجا با GNU Make و Makefile آشنا بشید. الآن بد نیست که خروجی دستور git status را ببینیم تا توضیحاتی در این‌باره بدیم (این دستور، وضعیت‌جاری مخزنمان را نشان می‌دهد) : $> git status On branch master No commits yet Untracked files: (use "git add <file>..." to include in what will be committed) Makefile header/ source/ nothing added to commit but untracked files present (use "git add" to track) عکس زیر را مشاهده‌کنید تا توضیح‌بهتری بدم : فایل‌های شما داخل گیت (git) دارای حالات‌های مختلفی‌هستن، به طورکلّی یا شناخته‌شدن‌اند (tracked) یا ناشناخته‌اند (untracked)؛ فایل‌ها/دایرکتوری‌هایی که ما بعد از مقدار‌‌دهی مخزن‌مان ساختیم، در حالت ناشناخته (untracked) هستند. که خود گیت (git) هم همین‌را به ما گفته‌است : Untracked files: (use "git add <file>..." to include in what will be committed) برای اینکه شناخته‌شده (tracked) بشند، باید آنها را به صحنه (stage) ببریم. برای اینکار خود گیت گفته‌است که باید چه کرد که می‌توانیم به دوصورت انجام دهیم : $> git add Makefile source header $> git add -A خب حالا دوباره خروجی git status را نگاه می‌کنیم : $> git status On branch master No commits yet Changes to be committed: (use "git rm --cached <file>..." to unstage) new file: Makefile new file: header/arg.c new file: source/arg.h الآن فایل‌های ما به stage رفتند، و آمادهٔ این‌هستند که گزارش‌ (commit) بشوند. دقت کنید که Git از خِیر دایرکتوری‌های خالی می‌گذرد. حالا کافیه‌که ما تغییراتی که دادیم را گزارش کنیم، که با دستور git commit به دوصورت انجام می‌شود : $> git commit $> git commit -m "My Message" در حالت‌اوّل، گیت ادیتور پیش‌فرضتان را باز می‌کند و از شما می‌خواهد که یک توضیح‌کوتاه درمورد تغییراتی‌که داده‌اید بنویسید، در حالت‌دوّم، شما مستقیم توضیح‌کوتاه خود را وارد می‌کنید. حال دوباره برگردیم و خروجی دستور git status را ببینیم : $> git status On branch master nothing to commit, working tree clean خیلی‌هم عالی، این نشان دهندهٔ این‌است که ماهیچ فایل ناشناخته (َUntracked) یا دستکاری‌شده (Modified) یا درصحنه (Stage) نداریم. هنگامی‌که تغییراتی را در فایل‌های شناخته‌شده (Tracked) بدید، آن فایل از حالت دستکاری‌نشده (Unmodified) به حالت دستکاری‌شده (Modified) درمیاید، که نیاز است شما تغییرات را درصورت‌نیاز وارد صحنه (Stage) کنید و بعد گزارش‌کنید (Commit). حال تغییراتی‌اعمال می‌کنیم، و مراحل‌مورد نیاز تا درصحنه (Stage) بردن‌فایل‌ها انجام می‌دهیم : $> git add -A $> git status On branch master Changes to be committed: (use "git reset HEAD <file>..." to unstage) modified: Makefile modified: header/arg.h modified: source/arg.c امّا شاید شما نخواید که مثلاً Makefile گزارش‌ش با مابقیه فایل‌ها یکی باشه، و نیاز دارید که از Stage بیرون بیاریدش؛ دقّت کنید خود Git هم راهنمایی‌ کرده که باید چه‌کار کرد : $> git reset HEAD Makefile $> git status On branch master Changes to be committed: (use "git reset HEAD <file>..." to unstage) modified: header/arg.h modified: source/arg.c Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: Makefile و حالا می‌توانید به راحتی گزارش فایل‌های خودتان را برای header/arg.h و source/arg.c بنویسید : $> git commit -m "Done With Print() Function" فایل .gitignore بیاید تا make را اجرا کنیم (درصورتی‌که با GNU Make آشنا نیستید، برای آشنایی این‌قسمت را مطالعه کنید) : $> git status On branch master Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: Makefile Untracked files: (use "git add <file>..." to include in what will be committed) build/ object/ no changes added to commit (use "git add" and/or "git commit -a") اینجا دایرکتوری‌های build و object هم اضافه شدند،امّا ما نیازی نداریم که Git این دایرکتوری‌ها را مدیریت کند، پس کافیه که یک فایل به اسم .gitignore‌ درست کنیم. و فایل‌ها و دایرکتوری‌هایی که نمی‌خواهیم Git آنها را دنبال کند را در آن ذکر کنیم : $> echo -e "/build/*\n/object/*" > .gitignore $> cat .gitignore /build/* /object/ $> git status On branch master Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: Makefile Untracked files: (use "git add <file>..." to include in what will be committed) .gitignore no changes added to commit (use "git add" and/or "git commit -a") و مشاهده می‌کنید که دیگر Git اخطاری برای دایرکتوری‌های build‌ و object نداد. خب دوستان،امیدوارم دلیل اهمیّت Git و کلاً برنامه‌های کنترل‌ورژن را درک‌کرده باشید؛ امّا شرمنده، دنیای Git بزرگ‌تر از آنچه هست که من بخوام خلاصه‌ای از هر قسمت را در یک پست باز‌گو کنم؛ شدیداً پیشنهاد می‌کنم که این‌کتاب را برای فراگیری هرچه بهتر Git‌ بخوانید. - موفق و پیروز باشید.
  3. 3 امتیاز
    با توجه به محبوبیت صنعت وِب، سال‌هاست زبان‌های برنامه‌نویسی در این زمینه پیشرفت‌ها و کاربرد‌های چشم‌گیری را داشته‌اند، از جمله جاوا‌اسکریپت (JS) به عنوان یک زبان قابل اجرا در داخل مرورگر شناخته می‌شود. هرچند بسیار محبوب و کاربردی است، اما این زبان قطعاً مشکلات خودش را دارد که برخی از آن‌ها عدم انعطاف‌پذیر بودن، سرعت پایین اجرا و همچنین انواع غیر ایمن آن است که این باعث می‌شود برای محاسبات و کارهای پیچیده جوابگو نباشد. هرچند گزینه‌هایی مانند CoffeeScript و TypeScript وجود دارند و نسبتاً ایرادات خام جاوا‌اسکریپتی را پوشش می‌دهند، اما در نهایت کد‌های نوشته شده به جاوا‌اسکریپت تبدیل می‌شود. در این میان می‌توان گفت وب‌اسمبلی (WebAssembly) برای حل و مرتب سازی مشکلات جاوا‌اسکریپت معرفی شده است و شدیداً در حال اثبات آن است که یک انقلاب در صنعت وِب را رقم می‌زند. با این تفاسیر، آیا وب‌اسمبلی زبان برنامه‌نویسی است؟ این فناوری به خودی خود، یک زبان برنامه‌نویسی نیست، در واقع برنامه‌نویسان برنامه‌های خود را توسط زبان‌های سطح‌بالا مانند C یا ++C و حتی Rust می‌نویسند و آن را کامپایل و در قالب باینری با پسوند فایل .wasm وارد می‌کنند. توجه داشته باشید که وب‌اسمبلی جایگزینی برای جاوا‌اسکریپت نیست، درواقع قرار است در کنار جاوا‌اسکریپت اجرا شود. به عنوان مثال شما می‌توانید فقط یک کد محاسباتی بالا را در WebAssembly بسازید و آن را در کنار سایر کد‌های جاوا‌اسکریپت با وزن سبک‌تر استفاده کنید. همچنین شما برای بارگذاری ماژول wasm در مرورگر به جاوا‌اسکریپت نیاز دارید. فناوری وب‌اسمبلی (WebAssembly) و یا WA چیست؟ وب‌اسمبلی یا وَسم (Wasm، اغلب به طور مخفف) استانداردی باز است که یک قالب جدید دستورالعمل‌های باینری را معرفی می‌کند. این فناوری نوید این را می‌دهد که برنامه‌ها با کارآیی (پرفرمنس) بومیِ خود در بستر وِب اجرا شوند. به عبارت ساده‌تر می‌توان گفت، این فناوری امکان این را می‌دهد که کد‌های نوشته شده با زبان‌های سطح بالا‌تر مانند C و ++C یا Rust به ماژول Wasm کامپایل شوند که مستقیماً در مرورگر‌های مدرن قابل اجرا هستند. معماری وب‌اسمبلی وب‌اسمبلی به گونه‌ای طراحی شده است که بر روی دستگاه‌های مجازی مبتنی بر پشته (stack-based) اجرا شود. بر خلاف ماشین‌های رجیستری که عملوند‌های آن‌ها بر روی پردازنده‌ی مرکزی قرار دارند و محاسبات در آن بخش اتفاق می‌افتد، در یک ماشین مبتنی بر پشته، بیشتر دستورالعمل‌ها به جای اینکه بر روی رجیستر اعمال شوند، بر روی پشته می‌نشینند. برای افزودن دو عدد بر روی ماشین مبتنی بر پشته، شماره‌های مربوطه را در پشته ارسال می‌کنید. سپس دستور ADD را فشار می‌دهید. سپس دو عملگر و دستورالعمل از بالای صفحه ظاهر می‌شود و نتیجه‌ی اضافی در جای خود قرار می‌گیرد. برخی از این نوع ماشین‌ها عبارتند از .Net، JVM Runtime و غیره. وب‌اسمبلی به معنای سنتی، پشته‌ای ندارد. درواقع هیچ مفهومی از اپراتور‌های جدید ندارد. حتی خبری از GC در آن وجود ندارد. در عوض وب‌اسمبلی دارای یک حافظه‌ی خطی است، یعنی حافظه به عنوان طیف پیوسته از بایت‌های بدون نوع نمایش داده می‌شود. در صورت نیاز به فضای بیشتر، ماژول وب‌اسمبلیِ شما می‌تواند بلوک حافظه‌ی خطی را افزایش دهد. نکته: WebAssemble فقط چهار نوع داده دارد: i32، i64، f32، f64 برای اعداد صحیح 32 و 64 بیتی و انواع شماره‌های شناور آینده‌ی توسعه‌ی وب چگونه می‌شود؟ اگرچه ممکن است وب‌اسمبلی، جاوا اسکریپت را از بین نبرد، اما قطعاً قصد این را دارد که چهره‌ی front-end توسعه‌ی وب را تغییر دهد. البته راه بسیاری در پیش است تا همه‌ی تغییرات را تجربه کنیم. اما به اندازه‌ی کافی می‌توان آینده‌ی وب را پیش‌بینی کنیم: تنوع از نظر زبانی خیلی سریع موازی تنوع زبانی این فناوری به طور چشم‌گیری تنوع در استفاده از زبان‌های برنامه‌نویسی را برای ساخت برنامه‌های تحت وب افزایش می‌دهد. در حال حاضر لیست زیر زبان‌هایی است که وب‌اسمبلی از آن‌ها پشتیبانی می‌کند: C/C++ Rust C#/.Net Java Python Elixir Go سرعت و کارآیی بسیار بالا فناوری WASM باعث می‌شود عملکرد برنامه‌ها شگفت‌انگیز شود. در این زمینه مستنداتی وجود دارد که فایرفاکس در یک سری از نمونه‌های اولیه آن را ثابت می‌کند. همچنین طبق تجزیه و تحلیل برنامه‌های کاربردی توسط فیگما منتشر شده است که نشان می‌دهد پیاده‌سازی‌های صورت گرفت در قالب asm.js که خود از سرعت بسیاربالای به خاطر پشتیبانی از سی++ دارد، با این وجود با فعال بودن ماژول WebAssembly چیزی حدود ۳ برابر بهبود زمان اجرا گرفته است. در این موارد ثابت شده است که با استفاده از ++C و کامپایلر کلنگ (LLVM) سرعت اجرای برنامه‌ها با فعال بودن وب‌اسمبلی بسیار چشم‌گیر است. موازی سازی طبیعتاً این مورد بسیار قابل بررسی و توجه است، چرا که این مبحث به طور کامل در وِب پیاده‌سازی نشده است. از آنجایی که تغییر به سمت پردازنده‌های چند هسته‌ای حدوداً از سال ۲۰۰۵ آغاز شد، این امر به طور فزاینده‌ای اتفاق می‌افتد که برای دستیابی به عملکرد بیشتر، نرم‌افزار‌ها به موازی سازی نیاز دارند. با توجه به اینکه جاوا‌اسکریپت از سیستم موازی پشتیبانی نمی‌کند، تصور کنید که با فعال‌سازی WASM امکان استفاده از تمامی هسته‌های پردازنده فراهم شود. من به عنوان نویسنده‌ی این مقاله، تصور شما را از این فناوری نمی‌دانم. اما قطعاً با این تفاسیر این فناوری به عنوان یک انقلاب بزرگ در حوزه‌ی وِب محسوب می‌شود. با توجه به ساختار برنامه‌های نوشته شده توسط زبان‌های قدرتمندی چون ++C می‌توان تصور کرد که برنامه‌های بسیار بهینه و قدرتمندی را در حوزه‌ی اجرایی مرورگر‌ها پشتیبانی کند. در حال حاضر ممکن استد شما فکر کنید که چرا کسی باید زبان ساده‌ای مثل جاوا‌اسکریپت را خدشه‌دار کند و یا به سمت زبان‌های پیچیده‌ای مانند Rust، C و ++C برود. اکنون وب‌اسمبلی کاملاً جدید است و جامعه‌ی کافی در اطراف خود ندارد. اما باید توجه داشت وقتی از طریق این فناوری می‌توان به ویدئو‌ها، تصاویر و کتابخانه‌های رمزنگاری، یا استفاده از موتور‌های گرافیکی و فیزیکی که از OpenGL استفاده می‌کنند، و یا حتی کتابخانه‌‌ها و فریم‌ورک‌های قدرتمندی مانند Qt و غیره را می‌توان در حوزه‌ی وب مورد استفاده قرار داد. بنابراین فناوری وب‌اسمبلی می‌تواند مسیری را برای رشد صنایع مختلف به خصوص شرکت‌های بازی‌سازی و غیره باز کند. افزایش کارآیی (پرفرمنس) بسیار شدید که توسط وب‌اسمبلی فراهم می‌شود، همانند اجرای برنامه‌های دسکتاپی است که می‌توان آن را بر روی وب نیز مشاهده کرد. با این روال ممکن است وب‌اسمبلی در سال‌های آینده، با نرم‌افزار‌های رومیزیِ بومی برابری کند.
  4. 3 امتیاز
    زبانی را انتخاب کنید که پاسخگوی برنامه‌ی تحت بلاک‌چین شما باشد! فناوری بلاک‌چین به سرعت در حال تبدیل شدن به یکی از مهمترین پیشرفت‌های فناوری در چند دهه‌ی گذشته است. این سیستم، معاملات ناشناس و همتا را بین کاربران امکان‌پذیر می‌کند که اساساً بر پایه‌ی انقلاب رمزنگاری است. بازار جهانی بلاک‌چین در حال حاضر حدود ۱.۲ میلیارد دلار تخمین زده می‌شود و کارشناسان پیش‌بینی می‌کنند که تا سال ۲۰۲۵ به ارزش ۵۷ میلیارد دلار برسد که در سال بیش از ۶۹ درصد رشد خواهد داشت. عمده‌ی شرکت‌ها و سرمایه‌دارانِ سرمایه‌گذار در توسعه‌ی فناوری جدید رمزنگاری، قرارداد‌های هوشمند دفترچه‌های توزیع‌شده برای بانک‌های سنتی، توکن‌های بازی و سیستم‌های مدیریت زنجیره تأمین با شرکت‌های مشاوره بلاک‌چین همکاری می‌کنند. توسعه‌دهندگان در حال حاضر از زبان‌های برنامه‌نویسی محبوبی مانند C++ و JavaScript برای ساختن برنامه‌های سفارشی بلاک‌چین استفاده می‌کنند. علاوه بر این، مهندسان رمزنگاری زبان‌هایی مانند Simplicty و Solidity را برای این کار طراحی کرده‌اند. اما، آن‌ها آیا این‌ها بهترین زبان‌های برنامه‌نویسی برای فناوری بلاک‌چین هستند؟ بلاک‌چین چیست؟ بانکداری سنتی از یک بانک به عنوان رهبر و واسط استفاده می‌کند. جهت انتقال پول به یک دوست، یک شخص ابتدا حسابی داشته باشد و بخواهد که پول را به یک شماره حساب خاص که برای اوست انتقال دهد. بانک، حساب ارسال کننده را برای وجه بررسی می‌کند و آن وجه را به مقصد منتقل می‌کند و معامله در حساب فرستنده ثبت می‌شد. همچنین بانک دریافت کننده نیز همین کار را باید انجام دهد. با این حال، مشکل سیستم بانکی سنتی این است که سوابق در داخل ذخیره می‌شوند و در برابر هک و دستکاری‌های آسیب‌پذیر هستند. بلاک‌چین با ذخیره کردن تمامی سوابق به صورت آنلاین در یک دفترچه‌ی مستعار (بی‌نام) ذخیره می‌کند که توسط هر کسی قابل دسترس است. بلاک‌چین از بلاک‌ها استفاده می‌کند، یا مجموعه‌ای از داده‌ها، مشابه سطر‌ها و ستون‌های صفحه‌های گسترده جهت ذخیره داده‌ها استفاده می‌کند. بلاک‌ها به ترتیب متوالی به «زنجیر» اضافه می‌شوند. برخلاف دفترچه‌های سنتی، که در داخل ذخیره می‌شوند، هر کاربرِ بلاک‌چین دارای سوابق کاملی از کل بلاک‌چین در رایانه‌ی خود است. این بدان معنی است که در صورت داشتن کد هش (رمز‌شده‌ی) مربوطه می‌توانند به سرعت هر معامله‌ای را که اتفاق افتاده است را پیدا کنند. از آن‌جایی که این داده‌ها به صورت عمومی ذخیره می‌شوند، هرگز قابل تغییر یا حذف نیستند! در نتیجه آرامش خاطر را به کاربران فراهم می‌کند. زبان برنامه‌نویسی JavaScript (جاوااسکریپت) از آن‌جایی که گیت‌هاب به تازگی این زبان را به عنوان محبوب‌ترین زبان برای توسعه‌دهندگان اعلام کرده است، به طور باورنکردنی بیش از ۹۵٪ وب‌سایت‌ها به طریقی از آن‌ استفاده می‌کنند. با این حال، جاوااسکریپت تنها پادشاه وب نیست؛ چرا که به عنوان یک زبان انعطاف‌پذیر در بلاک‌چین استفاده می‌شود. یکی از دلایلی که جاوااسکریپت را برای توسعه‌دهندگان می‌بخشد نحوه‌ی دستیابی به مدیریت کد‌ها به صورت ناهمزمان (ناهمگام) است. این امر در بلاک‌چین بسیار مهم است، زیرا ممکن است هزاران یا حتی میلیون‌ها معاملات در همان زمان آغاز شود! برنامه‌نویسی موازی یک برنامه را قادر می‌سازد تا چندین عمل را به صورت همزمان انجام دهد در حالی که برنامه‌نویسی استاندارد و همزمان نمی‌توانند آن حجم را تحمل و کنترل کنند. با اجرای چندین کار به صورت همزمان، کد ناهمزمان می‌تواند باعث افزایش پاسخگویی و عملکرد برنامه شود. این امر باعث می‌شود برنامه‌های بلاک‌چین بتوانند حجم بسیار زیادی از اقدامات را بدون عملکرد کُند و نا امید سازی کاربر، آن را انجام دهند. زبان برنامه‌نویسی C++ (سی‌پلاس‌پلاس) سی‌پلاس‌پلاس همچنین به عنوان یکی از قدرتمند‌ترین و محبوب‌ترین زبان‌های برنامه‌نویسی در دنیای فناوری شناخته می‌شود و در صنعت بلاک‌چین نیز یک قدرت غالب است. زبان شیء‌گرایی برای توسعه بلاک‌چین مناسب است، زیرا از همان اصول کپسوله‌سازی، انتزاع، چند‌ریختی و مخفی کردن داده‌ها استفاده می‌کند. به عنوان مثال بلاک‌چین از ویرایش‌های ناخواسته از داده‌ها جولوگیری می‌کند. توسعه‌دهندگان همچنین به دلیل قابلیت کنترل حافظه، از C++استفاده می‌کنند. این زبان به شما اجازه می‌دهد تا بلوک‌های ایمن را نگه‌ داشته و تعداد زیادی از درخواست منابع را مدیریت کنید. با اجازه دادن به هر نود (گره) شبکه می‌توانید بلوک‌های فردی را پذیرفته یا رد کنید. همچنین C++ به دلیل پشتیبانی و مدیریت وظایف موازی و نخی به طور گسترده در بلاک‌چین مورد استفاده قرار می‌گیرد. این زبان قادر به مدیریت هردو ویژگی موازی و غیرموازی در وظایف است، در واقع می‌تواند به خوبی انجام وظایف تک-نخی/تک رشته‌ای (single-thread) را بهبود دهد. نمونه‌ی فوق‌العاده‌ای از برنامه‌های اساسی از بلاک‌چین که با C++ نوشته شده است EOS نام دارد. این نرم‌افزار به صورت منبع‌باز در سال ۲۰۱۸ توسط بلاک منتشر شد و به گونه‌ای طراحی شده است که معاملات را سریع‌تر از گزینه‌های دیگر پردازش می‌کند. این نرم‌افزار اجازه می‌دهد تا در کمتر از یک ثانیه معامل را تأیید کرده و فقط در دو دقیقه آن را نهایی کنید. زبان برنامه‌نویسی Solidity این زبان یک نمونه‌ی هوشمند است که با همکاری توسعه‌دهندگان Ethereum و بلاک‌چین توسعه یافته است. این زبان به صورت اختصاصی دامنه‌های بسیاری از اصول و اصطلاحات مشابه به جاوا‌اسکریپت را برای ایجاد برنامه‌های با کیفیت بالا و غیر متمرکز فراهم می‌کند. توسعه‌دهندگان، این زبان را برای این ترجیح می‌دهد که به شما این امکان را فراهم می‌کند تا یک کد سطح بالا را برای شبکه‌ی بلاک‌چینی Ethereum، دومین بلاک‌چین رمزنگاری محبوب، که می‌تواند به زبان سطح پایین و کد ماشین کامپایل شود. در حال حاضر Solidity در طیف گسترده‌ای از سکو‌ها (پلتفرم‌های) بلاک‌چینی از جمله، Ethereum، Tendermint، Ethereum Classic و Counterparty موجود است. زبان برنامه‌نویسی Simplicity این یک زبان کاملاً جدید است که در تاریخ نوامبر ۲۰۱۷ برای قرارداد‌های خاص و هوشمندِ بلاک‌چین طراحی و منتشر شده است. این زبان برای افزایش بهره‌وری و پنهان‌سازی اجزای منطقی سطح پایین از مهندسان است که یکی از دلایلی است که به سرعت در جامعه محبوب می‌شود. مانند C++، این یک زبان شیء‌گرایی است که برای جولوگیری از خطاها و تغییر داده‌ها در بلاک‌چین استفاده می‌کند. خلاصه بلاک‌چین اینجاست تا بماند! فناوری محبوب (Record-Keeping) چیزی است که تبادلات رمزنگاری را ممکن می‌سازد و بطور گسترده توسط شرکت‌ها، افراد و خدمات مشاوره‌ای بلاک‌چین، برای توسعه‌ی نرم‌افزار مورد استفاده قرار می‌گیرد. توسعه دهندگان می‌توانند به راحتی از زبان‌های محبوب مانند C++ و JavaScript برای توسعه‌ی بلاک‌چین استفاده کنند. از طرفی این انجمن اخیراً زبان‌هایی به عنوان Solidity و Simplicity را ایجاد کرده است که باعث می‌شود تا فرآیند توسعه‌ی رمزنگاری روان‌تر شود.
  5. 3 امتیاز
    اصطلاحاتی که بهتر است در مورد C++ مدرن بدانید! داشتم به این فکر می‌کردم که برخی از مبتدیان برنامه‌نویسی به خصوص کسانی که به سراغ زبان‌هایی مثل سی++ می‌روند معمولاً مستقیم وارد کد نویسی می‌شوند و به این گمان که آغاز برنامه‌نویسی یعنی نوشتن یک کد با خروجی «سلام، دنیا»! دریغ از آن‌ که بعضی از موارد مانند «معرفی کامپایلر و انواع آن» و حتی «ساختار برنامه‌های نوشته شده تحت سی‌پلاس‌پلاس» و یا حتی «مدیریت حافظه» را در نظر بگیرند! من معمولاً در مقالات و آموزش‌های خودم به این اشاره می‌کنم که قبل از هر چیز باید با ساختار برنامه‌های نوشته شده‌ی یک زبان آشنا شد و سپس به بررسی موارد دیگر مانند نحو زبان و یا دیگر ویژگی‌های آن. بنابراین، یکی از خطرناک‌ترین عواملی که موجب خونریزی داخلی یک نرم‌افزار در برنامه‌های نوشته شده توسط برنامه‌نویس درC++ می‌شود عدم مدیریت حافظه‌ی اختصاص یافته است که باید بعد از اختصاص یافتن حافظه در زمان معین آن را آزادسازی کند. در صورتی که این کار صورت نگیرد عمل Memory Leak (نَشتِ حافظه) رخ داده است. بسیاری از علاقه‌مندان بر این باورند که چون سی++ دارای GC یا همان Grabbage Collector (زباله‌روب) نیست که البته صحیح است! سی++ دارای GC نیست و این امر محدودیت یا نکته ضعف آن هم نیست! سی++ همه چیز را آزادانه در اختیار برنامه‌نویس قرار می‌دهد تا خود در زمان مناسب روش مدیریت حافظه را انتخاب کند. در علوم رایانه بازیافت حافظه یا زباله‌روبی نوعی مدیریت حافظه‌ی خودکار است که عمل مدیریت حافظه‌های اختصاص یافته شده را به دست می‌گیرد و اکثر زبان‌های برنامه‌نویسی مانند #C، جاوا و دیگر موارد مشابه به آن مجهز به این ویژگی هستند که البته وجود چنین ابزار‌هایی می‌تواند توهمی را ایجاد کند مبنی بر آن که دیگر نیازی به مدیریت منابع نیست، اما در بعضی موارد مدیریت منابع هنوز یک الزام است چرا که منابع آزاد شده هنوز هم دلیل بر نشتِ حافظه هستند. این نشت حافطه زمانی اتفاق می‌افتد که اشیاء هنوز قابل دسترس از طرف اشیاءای که زنده هستند اما هرگز مورد استفاده‌ی دوباره قرار نمی‌گیرند اتفاق بی‌افتد. در بسیاری از زبان‌های برنامه‌نویسی این ویژگی وجود دارد که طبیعتاً مدیریت توسط GC راه حل بسیار خوب و بی نقصی نیست. اما با توجه به عدم وجود GC در سی++ اکثراً با روش‌های دستی برای مدیریت حافظه می‌پردازند که رایج‌ترین روش آن استفاده از عمل new و delete در اختصاص دادن و آزاد‌سازی حافظه است. بسیاری از ما با سی++ در دانشگاه و یا دروس مرتبط با مفاهیم اولیه برنامه‌نویسی آشنا شده ایم، اما معمولاً مفاهیم مربوطه برای نسل‌های قبلی و منسوخ شده‌ی این زبان است. بهتر است در نظر داشته باشید که برنامه‌نویسی مدرن یعنی پیروی از اصول و قوانین جدیدی که در تکامل یافتن یک زبان به کار گرفته می‌شود. RAII : Resource Acquisition is initialization بنابراین، باید در نظر گرفت مدیریت حافظه از استاندارد ۱۱ به بعد این زبان به روش‌های بسیار مدرن‌تری هوشمند سازی شده است. یکی از بهترین تکنیک‌های موجود در هسته‌ی زبان الگوی RAII است. تکنیک RAII مخفف «Resource Acquisition is initialization» به مفهوم (کنترل تخصیص منابع و آزاد‌سازی آن‌ها) یک ویژگی اصلی در سی‌پلاس‌پلاس است، که متکی به کامپایلر (همگردان) برای فراخوانی خودکار بعضی موارد عنوان می‌شود. با قرار دادن چنین کدی در مخرب (ویرانگر) دیگر به فراخوانی آن کد توسط برنامه‌نویس نیست و کامپایلر خود این کار را انجام می‌دهد. به طور کلی این الگو هر شیء را مجبور می‌سازد تا در زمان مواجه با رفتار‌های ناهنجار خود را پاکسازی کند. به طور کلی هنگامی که شما یک شیء را مقدار‌دهی اولیه می‌کنید، قبل از انجام آن باید منابع مورد نیاز آن را تأمین کنید (در سازنده). هنگامی که یک شیء از محدوده‌ خارج می‌شود، هر منبعی را که مورد استفاده قرار داده است باید آزاد کند (در مخرب - ویرانگر). نکات کلیدی هرگز نباید یک شیء به حالت نیمه آماده یا نیمه از بین‌ رفته وجود داشته باشد! وقتی که یک شیء ساخته می‌شود، آن شیء باید در حالت آماده باش برای استفاده باشد. وقتی یک شیء از محدوده خارج می‌شود، باید منابع اختصاص یافته‌ی خود را در حافظه آزاد کند (کاربر مجبور به انجام کار دیگری نیست). آیا RAII عنوان بدی برای مفهوم این تکنیک است! از نظر خالق سی‌پلاس‌پلاس نام بهتر می‌تواند به صورت زیر باشد: مدیریت منابع مبتنی بر حوزه (محدوده یا دامنه) : Scope Based Resource Management چیزی که تکنیک RAII را نقض می‌کند چیست؟ اشاره‌گر‌های خام و تخصیص حافظه فراخوانی با کلمه‌ی کلیدی new برای دست آوردن یا اختصاص دادن منبع (حافظه). فراخوانی با کلمه‌ی کلیدی delete برای آزاد‌سازی منبع (حافظه). اما این مورد به صورت خودکار بعد از خروج از محدوده توسط اشاره‌گر‌ها صورت نمی‌گیرد. void rawPtrFn() { // acquire memory resourceNode* n = newNode; // manually release memory delete n; } بنابراین در صورتی که برنامه‌نویس استفاده از کلمه‌ی کلیدی delete را برای آزاد‌سازی حافظه فراموش کند (نشتِ حافظه) رخ می‌دهد. بنابراین این عمل کافی است تا تکنیک RAII را نقض کنیم. void UseRawPointer() { // Using a raw pointer -- not recommended. Song* pSong = new Song(L"Nothing on You", L"Kambiz Asadzadeh"); // Use pSong... // Don't forget to delete! delete pSong; } بنابراین، راه حل RAII برای این امر در چیست؟ کلاسی داشته باشید که : حافظه را هنگام مقدار‌دهی اولیه تخصیص دهد. حافظه را هنگام فراخوانی مخرب (ویرانگر) آزاد کند. دسترسی به اشاره‌گر‌های زیرین را امکان‌پذیر کند. اشاره‌گر‌های هوشمند (Smart Pointers) این ویژگی اساساً مدیریت حافظه‌ی خودکار را ارائه می‌دهد. زمانی که یک اشاره‌گر هوشمند دیگر استفاده نمی‌شود (زمانی که از محدوده‌ی خود خارج می‌شود) حافظه‌ی مورد نظر خود را به طور خودکار آزاد می‌کند.توجه داشته باشید که اشاره‌گر‌های سنتی با عنوان اشاره‌گر‌های خام (Raw Pointer) شناخته می‌شوند. اشاره‌گر‌های هوشمند را می‌تواند یک شکل کلی از GC در نظر گرفت؛ نوعی مدیریت خودکار وقتی که دیگر توسط برنامه مورد استفاده قرار نمی‌گیرند حافظه‌ی اختصاص یافته‌ی آن شیء به طور خودکار حذف می‌شود. در استاندارد ۱۱ سی‌پلاس‌پلاس سه نوع اشاره‌گر هوشمند معرفی شده است که همه‌ی آن‌ها در فایل سرآیند <memory> از کتابخانه‌ی استاندارد STL معرفی شده‌اند. کلاس std::unique_ptr یک اشاره‌گر هوشمند که دارای یک منبع تخصیص حافظه‌ی پویا است. کلاس std::shared_ptr شامل یک اشاره‌گری است که دارای یک منبع تخصیص حافظه‌ی پویا با تفاوت اینکه می‌تواند چندین شیء را به صورت اشتراکی از یک منبع مشترک ردیابی کند. کلاس std::weak_ptr مانند std::shared_ptr است که شمارنده‌ی آن افزایش نمی‌یابد. به مثال زیر توجه کنید: { std::unique_ptr<int> p(new int); // شیء p قابل استفاده در داخل حوزه است. } // در این بخش که خارج از دامنه‌ی اشاره‌گر است حافظه‌ی اختصاص یافته آزاد می‌شود. همانطور که مشخص است یک شیء که تحت اشاره‌گر هوشمند مورد استفاده قرار می‌گیرد تا زمانی که خارج از حوزه‌ی خود قرار نگیرد قابل استفاده خواهد بود. نمونه کد پایین مثالی از نحوه‌ی نمونه سازی تحت اشاره‌گر‌های هوشمند است. void UseSmartPointer() { // Declare a smart pointer on stack and pass it the raw pointer. unique_ptr<Song> song2(new Song(L"Nothing on You", L"Kambiz Asadzadeh")); // Use song2... wstring s = song2->duration_; //... } // song2 is deleted automatically here. این مقاله در یک فرصت مناسب به به جزئیاتی بیشتری خواهد پرداخت
  6. 3 امتیاز
    واقعا دست شما درد نکنه که این همه وقت گذاشتید برای تولید این کتاب با ارزش این کتاب هم از صفر شروع کرده و قدم به قدم کاربر رو به سمت طراحی حرفه ای رابط کاربری با کیوت و کیو ام ال برده البته بیشتر روی طراحی رابط کاربری تمرکز کرده و کمتر به مسائل دیگه پرداخته که خب توی این کتاب جاشون هم نبوده ولی در کل عالی هست . معرفی انواع مختلف با توضیحاتی در مورد کارکردشون و نمونه کد های زیاد برای بهتر جا افتادن مطلب و در کل همه چیز دست به دست هم داده تا این کار خوب از آب در بیاد . به نظرم این برای کسی که بخواد طراحی رابط کاربری با کیوت و کیو ام ال رو یاد بگیره خیلی عالیه و کافی هست یعنی اگر کسی پا به پای این کتاب کد بزنه و پیش بره در انتهای کتاب میتونه به راحتی هر برنامه ای رو به سرعت و با دقت طراحی کنه رابط کاربریش رو واقعا عالیه .
  7. 2 امتیاز
    سلام. عدم دسترسی به یک سیستم مناسب و با خبر نبودن از حساب کاربری گیت هاب خود یکی از مشکلاتی بود که در این چند ساله برنامه نویسان با آن روبرو بودند. چک کردن حساب ایمیل در تلفن همراه می توانست تا حدودی به این موضوع کمک کند. اما یک اپلیکیشن اختصاصی برای این مورد می تواند این امر را به بهترین شکل پوشش دهد. بعد از کارهایی که برروی اپلیکیشن رسمی شرکت گیت هاب برای پلتفرم iOS انجام شد و خوشبختانه بدون هیچ مشکلی در بزرگ رویداد و کنفرانس شرکت و مایکروسافت - GitHub Universe 2019 در تاریخ November 13-14, 2019 رونمایی شد. به عنوان یکی از اعضای شرکت این نوید را می دهم که نوبت به آن رسید تا اپلیکیشن برای اندروید نیز پیاده شود. در حال حاضر این اپلیکیشن در حال توسعه است و هنوز رونمایی نشده است. برای این اپلیکیشن میزان پشتیبانی API 21+ Android device در نظر گرفته شده است و خواهد توانست از نسخه Android 5.0 به بالا را پشتیبانی کند. می توانید پیشنهادات و نظرات خود را نیز ایمیل کنید. Max [@] Asrez {.DOR.} com Hi, I'm Max Base. GitHub team did work on the official GitHub application for the iOS platform and fortunately unveiled at the big event and conference(GitHub Universe 2019 on November 13-14, 2019). As a member of the company, I have the promise that the app will launch for Android. This app is currently under development and has not been unveiled yet. This app is designed to support Android 21+ API and will support Android 5.0 or later. You can also email your suggestions and comments. Max [@] Asrez {.DOR.} com Best, Max Base با تشکر Max Base / مکس بیس
  8. 2 امتیاز
    آموزش زبان برنامه‌نویسی سوئیفت - جلسه چهارم مواردی که در این جلسه یاد خواهید گرفت: کامنت‌ها، دو ویژگی نوع‌های داده Int، آپِریِتر‌ها ( Operators )، کلمات کلیدی break,continue,fallthrough عرض ادب و احترام دارم خدمت شما عزیزان. در این جلسه به مواردی که در بالا گفته شده، پرداخته میشه، پس تا انتها با من همراه باشید و امیدوارم از این جلسه هم نهایت استفاده رو بکنید. کامنت‌ها در زبان برنامه‌نویسی سوئیفت مثل اکثر زبان‌های برنامه‌نویسی دیگه، از کامنت‌ها استفادهای زیادی میشه و معمولا برای هدفی کامنت‌ها نوشته میشن و می‌تونن شامل موارد زیر باشن: برای غیر‌فعال کردن موقتی یک قسمت/بخش از کُد برای توضیح دادن یک قسمت/بخش از کُد برای دیگر برنامه‌نویسان/توسعه‌دهندگان یا توضیح کُد برای اینکه در مراجعات بعدی به کُدهای پروژه کارکرد هر قسمت از برنامه را متوجه شوید انواع کامنت‌ها در زبان برنامه‌‌نویسی سوئیفت: تَک خطی (‌ single-line ) چند خطی ( multi-line ) در کامنت تَک خطی، با گذاشتن دو علامت // می‌توانید توضیحات خود را فقط در همان خط درمورد کُد مورد نظر بنویسید و بعد از آن کامنت شما در واقع در حال تعریف دستور جدید هستید! به این مثال دقت کنید: let _web_site_name : String = "www.iostream.ir" print(_web_site_name) // Ouput the string of www.iostream.ir در مثال بالا همان‌طور که مشاهده می‌کنید از کامنت تَک خطی استفاده کردیم، و بعد از این کامنت شما نمی‌توانید انتظار داشته باشید که در خط جدید دوباره حالت کامنت‌گذاری برای شما همچنان فعال باشد! چرا که در بعدی دستوری جدید داریم نه کامنتی ادامه‌ی کامنت قبل!. و اما کامنت چند خطی که اسمش هم روشه، تا هر چند‌تا خط تا موقعی که آخر کامنت رو نَبسته باشید، می‌تونید توضیحات بنویسید. به مثال زیر دقت کنید: let _web_site_name : String = "www.iostream.ir" /* We can also use from of print("String.. and \(_web_site_name)") */ print(_web_site_name) در مثال بالا که مشاهده می‌کنید، شما هیچ محدودیتی برای اضافه کردن توضیحات بیشتر برای کُد‌های خود ندارید و تا هر چند خط توضیحات می‌توانید استفاده کنید. دو ویژگی نوع داده‌ی Int اگر بخواهیم کوچک‌ترین و بزرگ‌ترین عدد موجود از نوع داده‌ی Int را بدست آوریم، از دو ویژگی max,min استفاده می‌کنیم. هر دو ویژگی به همراه مثال در زیر آورده شده‌اند: print("Max => \(Int.max)") print("Min => \(Int.min)") با اجرای کد‌های بالا،‌ بزرگترین مقدار موجود نوع داده‌ی Int و همچنین کوچک‌ترین آن به شما نمایش داده می‌شود. آپِریِتر‌ها (‌ Operators ) آپِریِتر‌ها در هر زبان برنامه‌نویسی به عنوان پایه و اساس محاسبات و در بعضی موارد برای کارهای دیگر استفاده می‌شود. محاسباتی مانند، جمع، تفریق،تقسیم،ضرب و باقی مانده. در سوئیفت این 8 دسته آپرِیِتر وجود دارد: آپِریِتر‌ اِنتسابی ( Assigment Operator ) آپرِیِتر‌های محاسباتی ( Arithmetic Oprerator ) آپِریِتر‌ باقی‌مانده ( Remainder Operator ) آپِریِتر‌های مُرکب ( Compound Assigment Operator ) آپِریِتر‌های مقایسه‌ای ( Comparison Operators ) آپِریِتر ترِنِری ( Ternary Conditonal Operators ) آپِریِتر دامِنه ( Range Operator ) آپِریِتر‌های منطقی ( Logical Operators ) این‌ها، کل آپِریِتر‌ها در سوئیفت هستند که هر کدام عمل مخصوص به خود را انجام می‌دهند. در مثال‌های زیر هر کدام از این آپِریِتر‌ها را به همراه مثال برای شما آورده‌ایم. آپِریِتر‌های اِنتسابی ( Assigment Operator ) در کل اینکه ما یک مقداری را به متغییری انتساب می‌دهیم، عملا داریم از آپِریِتر‌‌ انتساب ( = ) استفاده می‌کنیم. چرا که کُدنویسی از سمت چپ شروع می‌شود و کاملا منطقی هم هست که مقدار دهی به یک متغییر از سمت چپ صورت می‌گیرد که مقدار سمت راست قرار می‌گیرد، با استفاده از آپِریِتر انتساب (‌ = ) در مابین مقدار و نام و نوع متغییر قرار می‌گیرد و عمل انتساب مقدار به متغییر را انجام می‌دهد. به مثال زیر دقت کنید: let _web_site_name : String = "www.iostream.ir" // Assigment Operator ( = ) print("Type of \(type(of : _web_site_name ) and the website of name \(_web_site_name)") در مثال بالا مشاهده می‌کنید که با استفاده از آپِریَتر انتساب (‌ = )‌، مقدار www.iostream.ir که یک مقدار رشته‌ای/متنی است را در متغیر web_site_name ذخیره می‌کنیم. در خط بعد هم نوع متغییر و مقدار موجود در متغییر web_site_name ذخیره نمایش می‌دهیم. آپرِیِتر‌های محاسباتی ( Arithmetic Oprerator ) در قسمت‌هایی از پروژه شده که ما باید محاسباتی رو انجام بدیم. این کار با استفاده از آپِریِتر‌های محاسباتی ( Arithmetic Operator ) صورت می‌گیرند. این آپِریِتر‌ها شامل: +،-،/،* و ٪ است. برای هر کدام از این آپریِترها، مثال‌هایی در زیر آورده شده است: آپِریِتر + var number_one, number_two : Int8 number_one = 50 number_two = 50 print("Result = > ", number_one + number_two) // Output the number 100 در مثال بالا همان طور که مشاهده می‌کنید، ابتدا دوم متغییر با نوع Int8 تعریف کرده و سپس در خطوط بعد به آن‌ها مقادیر ۵۰ را داده‌ایم. در نهایت عمل جمع ( + ) را روی آن‌ها به صورت مستقیم انجام و نمایش می‌دهیم. یا ساده‌تر بخواهیم تعریف کنیم، آپِریِتر ( + ) عمل جمع کردن اعداد و یا متصل کردن دو رشته را بر عهده دارد: var web_site_name, platform_name : String web_site_name = " www.iostream.ir :)" platform_name = " www.fanoox.com ;)" print("Binding two string => ", web_site_name + platform_name) // Ouput the website name and platform name => www.iostream.ir :) www.fanoox.com ;) و به همین راحتی می‌توانید تا بی‌نهایت عمل جمع و متصل کردن رشته‌ها را انجام دهید. تنها نکته‌ای که باید توجه داشته باشید این است که سوئیفت در برخورد با اعداد و این آپِریَتر، آن عبارت را محاسباتی در نظر می‌گیرد و در برخورد دو تا چند رشته، آن عبارت را عمل متصل کردن و الحالق ( concatentation ) در نظر می‌گیرد. آپِریِتر - این آپِریِتر برای کم کردن دو مقدار عددی از هم استفاده می‌شود، همان‌طور که در مثال زیر مشاهده می‌کنید: var number_one, number_two : Int8 number_one = 80 number_two = 30 print("Result => ", number_one - number_two) // Output the number 50 مثال بالا به خوبی نشان می‌دهد که دو مقدار ۸۰ و ۳۰ از هم کم شده با استفاده از آپِریِتر ( - ) و در نتیجه، خروجی برابر ۵۰ خواهد بود. آپِریِتر * این آپِریِتر عمل ضرب کردن دو عدد را انجام می‌دهد، به مثال زیر دقت کنید: var number_one, number_two : Int8 number_one = 50 number_two = 20 print("Result => ", number_one * number_two) // Output the number 1000 آپِریِتر ( *‌ ) عمل ضَرب را انجام می‌دهد و نباید به حرف ( x ) که شبیه به ضرب در ریاضیات است اشتباه گرفته شود. آپِریِتر / این آپِریِتر عمل تقسیم کردن دو عدد را انجام می‌دهد. به مثال زیر دقت کنید: var number_one, number_two : Double number_one = 50.0 number_two = 20.0 print("Result => ", number_one / number_two) // Output the number 2.5 در محاسباتی که عمل تقسیم را انجام می‌دهیم باید به این نکته دقت کنیم که اگر پروژه‌ی ما عملا برای محاسبات کار خاصی است باید از نوع داده‌ی Double یا Float استفاده کنیم که البته در محاسبات معمولی، نوع داده‌ی Float جواب‌گوی نیاز ما هم هست، اما در محاسباتی که نیاز به دقت بالایی دارند باید از نوع داده‌ی Double استفاده کنیم. آپِریِتر ٪ این آپِریِتر را با علامت درصد که شبیه همین است اشتباه نگیرید! چرا که در دنیای واقعی ما، علامت درصد برای نشان دادن مقداری از چیزی در یک محصول یا خدمات است ولی در دنیای کامپیوتر و برنامه‌نویسی این علامت که آپِریِتر خوانده می‌شود، به معنای باقی مانده‌ی بین دو عدد است که بعد از تقسیم‌های پی‌درپی که صورت می‌گیرد، بدست می‌آید. این باقی مانده یا ۰ است یا ۱. حتما شما هم عاشق صفر و یکی هستید که اساس کار کامپیوتر و سیستم شما را تشکیل می‌دهد!. یک مثال در زیر ببینید تا متوجه کارکرد این آپِریِتر شوید: var number_one, number_two : Int8 number_one = 10 number_two = 2 print("Result => ", number_one % number_two) // Output the number 0 اگر جزئی بخواهیم وارد شویم به این صورت است که ابتدا عدد ۱۰ بر ۲ تقسیم ( آپِریِتر / ) شده و سپس حاصلی که بدست می‌آید ۵ است و سپس همین ۵ دوباره تقسیم بر ۲ شده و ۲ بدست می‌آید و در اینجا ۲ ٪ ۲ می‌شود ۰. آپِریِتر باقی‌مانده ( Reminder Operator ) این آپِریِتر همان‌طور که در بالا و در قسمت آپِریِتر‌های محاسباتی قرار گرفته بود، کار محاسبه‌ی باقی‌مانده‌ی دو عدد را انجام می‌دهد: var number_one, number_two : Int8 number_one = 10 number_two = 2 print("Result => ", number_one % number_two) // Output the number 0 آپِریِتر‌های مُرکب ( Compound Assigment Operator ) که شامل عبارت‌های کوتاه‌شده یا به اصطلاح میانبُری برای عمل انتساب و محاسبه را فراهم می‌کند که شامل: =+،=-،=*،=/،=٪ است. در زیر توضیح مختصر به همراه یک مثال آورده شده است. آپِریِتر =+ در این حالت ما هم عمل انتساب را داریم و هم عمل جمع، با یک تیر دو نشان! به مثال زیر دقت کنید. var number_one : Int8 = 50 number_one += 50 print("Result =>", number_one) // Output the number 100 در خط دوم که ما با آن کار داریم، متغییر number_one به علاوه‌ی مقدار قبلی خودش، مقدار ۵۰ را هم به آن اضافه کرده و در نهایت در خود متغییر number_one ذخیره و نتیجه ۱۰۰ نمایش داده می‌شود. که بدون استفاده از میانبُر، به این شکل بود: var number_one : Int8 = 50 number_one = number_one + 50 print("Result =>", number_one) // Output the number 100 حتی می‌توانیم برای اتصال یک رشته به رشته‌ی دیگر استفاده کنیم: var web_site_name : String = "www.iostream.ir :) " web_site_name += " www.fanoox.com ;) " print("Result =>" web_site_name) // Ouput the web site of name => www.iostream.ir :) www.fanoox.com ;) که بدون استفاده از میانبُر به این شکل نوشته می‌شُد: var _web_site_name_and_platform_name : String = "www.iostream.ir :) " + " www.fanoox.com ;) " print("Result => ", _web_site_name_and_platform_name) // Ouput the web site of name and platform name => www.iostream.ir :) www.fanoox.com ;) آپِریِتر =- عمل تفریف و انتساب آن به مقدار فعلی متغییر را انجام می‌دهد. به مثال زیر دقت کنید:‌ var number : Int8 = 80 number -= 30 print("Result =>", number) // Ouput the number 50 مقدار ۸۰ که مقدار فعلی متغییر number است، از مقدار ۳۰ که در سمت راست متغییر قرار دارد، کم می‌شود و در نهایت مقدار ۵۰ در همان متغییر یعنی ‌number ذخیره می‌شود. آپِریِتر =* عمل ضرب و انتساب مقدار سمت راستی در مقدار فعلی متغییر سمت چپ را انجام می‌دهد. به مثال زیر دقت کنید: var number : Int8 = 80 number *= 30 print("Result =>", number) // Ouput the number 2400 آپِریِتر =/ مشابه آپِریِتر تقسیم ( / )‌، عمل تقسیم و انتساب آن به متغییر سمت چپ انجام می‌دهد. به مثال زیر دقت کنید: var number : Int8 = 10 number /= 2 print("Result =>", number) // Ouput the number 5 آپِریِتر =٪ عمل باقی‌مانده‌ی دو عدد که شامل مقدار فعلی متغییر سمت چپ و مقدار سمت را است را محاسبه کرده و در متغییر سمت چپ ذخیره می‌کند. به مثال زیر دقت کنید: var number : Int8 = 10 number ٪= 5 print("Result =>", number) // Ouput the number 0 آپِریِتر‌های مقایسه‌ای ( Comparison Operators ) برای مقایسه‌ی بین دو مقدار و در نتیجه برگرداندن مقدار True یا False مورد استفاده قرار می‌گیرند. بیشترین استفاده‌ی آنها در شرط‌هاست، اما می‌توان به صورت مستقیم هم از آن‌‌ها هم استفاده کرد. این آپِریِتر‌ها شامل ==،=!،>،<،=<،=>،==!،=== است. برای هر کدام مثالی در زیر آورده شده است. آپِریِتر == برای مقایسه دو مقدار استفاده می‌کنیم که مقدار در صورتی که مقادیر دو طرف مساوی باشند، مقدار True و در غیر اینصورت مقدار False برگشت داده می‌شود. به مثال زیر دقت کنید: print("True and False => ", 2 == 2) // Output the true print("True and False => ", 2 == 3) // Output the false در مثال بالا چونکه ۲ با ۲ برابر است،‌ مقدار نمایش داده شده،‌ true است. و در خط بعدی چونکه مقدار ۲ برابر با ۳ نیست،‌ مقدار false نمایش داده می‌شود.همچنین می‌توانید در شرط‌ها و حلقه‌ها هم استفاده کنید: if 2 == 2 { print("Ok!") }else { print("NO!") } // Ouput the string Ok! آپِریِتر =! اگر مقدار برابر با مقدار مقابل خودش نبود، نتیجه true و در غیر اینصورت نتیجه false خواهد بود. علامت ! ( نَقیض )‌ دقیقا معنا و مفهوم ( == ) را عوض می‌کند. به مثال زیر دقت کنید: print("True and False => ", 2 != 3) // Output the true print("True and False => ", 2 != 2) // Output the false در مثال بالا، ۲ مساوی ۳ نیست و این درست است. در خط بعدی ۲ مساوی با ۲ نیست که این درست نیست و مساوی هستش،‌ پس نتیجه false است. آپِریِتر > اگر مقدار سمت چپ کوچکتر از مقدار سمت راست بود، نتیجه true و در غیر اینصورت نتیجه false است. به مثال زیر دقت کنید:‌ print("The operator ( < ) => ", 1 < 2) // Output the boolean true print("The operator ( < ) => ", 2 < 1) // Output the boolean false آپِریِتر <‌ اگر مقدار سمت چپ بزرگتر از مقدار سمت راست بود، نتیجه true و در غیر اینصورت نتیجه false است. به مثال زیر دقت کنید: print("The operator ( > ) => ", 1 > 2) // Output the boolean false print("The operator ( > ) => ", 2 > 1) // Output the boolean true آپِریِتر =< اگر مقدار سمت چپ، بزرگتر یا مساوی مقدار سمت راست بود، نتیجه true است، در غیر اینصورت، نتیجه false خواهد بود. به مثال زیر دقت کنید: print("The operator ( >= ) => ", 1 >= 1) // Output the boolean true print("The operator ( >= ) => ", 1 >= 2) // Output the boolean false آپِریِتر => اگر مقدار سمت چپ، کوچکتر یا مساوی مقدار سمت راست بود، نتیجه true است، در غیر اینصورت، نتیجه false خواهد بود. به مثال زیر دقت کنید: print("The operator ( <= ) => ", 1 <= 2) // Output the boolean false print("The operator ( <= ) => ", 1 <= 1) // Output the boolean true نکته:‌ اولویت آپِریِتر مساوی (‌ = ) در این مورد بالا‌تر از آپِریِتر < یا > است و بنابر این در حلقه‌ها اگر این این آپِریِتر باشد، مبنا بر همین آپِریِتر قرار می‌گیرد. آپِریِتر === این آپِریِتر برای مقایسه‌ی دو شئ ( object ) استفاده می‌شود. اگر هر دو شئ از یک مرجع ( refrence ) بودند یا به عبارت دیگر شئ‌های ساخته شده در حافظه‌ی به نام Heap با تمام ویژگی‌ها و متغییر‌‌ها نگه‌داری می‌شوند و اگر شئ دیگر از همان حافظه‌ای که یک شئ دیگر استفاده می‌کند باشد، این آپِریِتر درمورد آن دو شئ نتیجه‌ی true و در غیر اینصورت نتیجه‌ی false را نمایش می‌دهد. در مبحث شئ‌گرایی بیشتر در این مورد صحبت ‌می‌کنیم،‌ در حال حاضر فقط همین را بدانید، کافیست. به مثال زیر دقت کنید: class WebsitePlatform { var web_site_name, platform_name : String init(web_name : String, platform : String) { self.web_site_name = web_name self.platform_name = platform } } let _web_site_and_plat_form_one = WebSitePlatform(web_name : "www.iostream.ir", platform : "www.fanoox.com") let _web_site_and_plat_form_two = WebSitePlatform(web_name : "www.iostream.ir", platform : "www.fanoox.com") if _web_site_and_plat_form_one === _web_site_and_plat_form_two { print("This is refrence!") }else { print("No,this is not refrence!") } اگر این کُد را خروجی بگیرید، به شما پیغام NO, this is not refrence را می‌دهد. چرا که هر دو شئ به صورت جداگانه در حافظه‌ی Heap ذخیره شده‌اند و هیچ‌کدام به دیگر کاری ندارد و به اصطلاح با هم ارتباطی ندارند و هر یک کَشک خودش را می‌سابد. و اگر ما بیایم به این شکل عمل کنیم، آنوقت دیگر یک ارجاع داریم به شئ‌ای مشخص: class WebsitePlatform { var web_site_name, platform_name : String init(web_name : String, platform : String) { self.web_site_name = web_name self.platform_name = platform } } let _web_site_and_plat_form_one = WebSitePlatform(web_name : "www.iostream.ir", platform : "www.fanoox.com") let _web_site_and_plat_form_two = _web_site_and_plat_form_one if _web_site_and_plat_form_one === _web_site_and_plat_form_two { print("This is refrence!") }else { print("No,this is not refrence!") } به جای ایجاد شئ جدید، همان شئ اول را به متغییر دوم انتساب می‌دهیم که الان در واقع دو شئ داریم که شئ دومی به شئ اولی اشاره می‌کند و حالا باید این دو شئ، دوتایی کَشک بسابن! یعنی اینکه الان دوتایی به هم در ارتباطن و شئ دومی ارجاعیست به شئ اول. نتیجه خروجی هم This is refrence است. آپِریِتر ==! اگر دو شئ از یک مرجع نبودند، و هر کدام در حافظه‌ای جداگانه نگه‌داری می‌شدند، نتیجه به صورت true و اگر دو شئ‌ از یک مرجع بودند، نتیجه false خواهد بود. کاملا برعکس آپِریِتر (‌ ===‌ ). به مثال زیر دقت کنید: class WebsitePlatform { var web_site_name, platform_name : String init(web_name : String, platform : String) { self.web_site_name = web_name self.platform_name = platform } } let _web_site_and_plat_form_one = WebSitePlatform(web_name : "www.iostream.ir", platform : "www.fanoox.com") let _web_site_and_plat_form_two = WebSitePlatform(web_name : "www.iostream.ir", platform : "www.fanoox.com") if _web_site_and_plat_form_one !== _web_site_and_plat_form_two { print("This is refrence!") }else { print("No,this is not refrence!") } مثال بالا هم که کاملا واضح است! اینکه اگر دو شئ با هم ارجاعی نداشتند، پس نتیجه طبق این آپِریِتر true است و در غیر اینصورت اگر ارجاع داشتند، نتجیه false و شرط آخر اجرا خواهد شد که No, this is not refrence است. آپِریِتر ترِنِری ( Ternary Conditonal Operators ) سه تا قسمت داره: مسئله/شرط مقدار اول مقدار دوم شرط در ابتدا قرار می‌گیره و سپس به دنبال آن آپِریِتر ? و بعد از آن جواب اول در صورت درست بودن شرط که برگشت داده می‌شود و علامت کالُن ( : ) در صورتی که نتیجه نادرست یا false باشد در شرط، مقدار بعد از کالُن/دونقطه ( : ) برگشت داده می‌شود. به مثال زیر دقت کنید: let _web_site_name_and_platform_name : String = 2 > 1? "www.iostream.ir" : "www.fanoox.com" print("Result =>", _web_site_name_and_platform_name) // Output the www.iostream.ir در مثال بالا همان‌طور که مشاهده می‌کنید، ابتدا شرط/مسئله قرار می‌گیرد و سپس مقدار بعد آپِریِتر ? و مقدار اول و دوم که با کالُن ( : ) از هم جدا می‌شوند. در این مثال نتیجه، www.iostream.ir است، چرا که ۲ بزرگتر از ۱ است و این از لحاض منقطی نتیجه‌ی true دارد. آپِریِتر دامِنه ( Range Operator ) این آپِریِتر در حلقه‌ها استفاده می‌شود و نحوه‌ی کار آن‌ را در جلسات قبل توضیح داده‌ام: for index_number_one in 0...20 { print(index_number_one, separator : " ",terminator : "") // Output the number 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 } for index_number_two in 0..<20 { print(index_number_two, separator : " ",terminator : "") // Output the number 0 1 2 3 4 5 6 7 8 9 10 11 12 13 15 16 17 18 19 } آپِریِتر‌های منطقی ( Logical Operators ) شامل آپِریِتر‌های !،&&،|| است. که بیشتر استفاده‌ی آن‌ها در حلقه‌هاست، اما شما می‌توانید در هر جایی از پروژه‌ی خودتان که نیاز به این آپِریِتر‌ها داشتید، به صورت مستقیم استفاده کنید. آپِریِتر ! ( نَقیض ) کار این آپِریِتر، برعکس کردن یا نَقیض کردن یک مقدار هستش که ممکنه true یا false باشه. به عنوان مثال اگه مقدار متغییری true بود و این آپِریِتر رو در ابتدای اون مقدار قرار دادید، خروجی برابر است با false. و همین مورد هم برعکس صدق می‌کند، یعنی اگر شما مقدار متغییری false داشتید، با گذاشتن این عبارت در ابتدای متغییر، نتیجه true می‌شود. این مثال زیر را ببینید: var is_name_web_site_iostream : Bool = false print(!is_name_web_site_iostream) // Output the bool true is_name_web_site_iostream = true print(!is_web_site_iostream) // Output the bool false آپِریِتر && اگر در شرط یا عبارتی بخواهیم دو شرط را بررسی کنیم که هر دو هم حتما باید درست ( true ) باشند از این آپِریِتر استفاده می‌کنیم. به مثال زیر دقت کنید: let web_site_name, platform_name : String web_site_name = "www.iostream.ir" platform_name = "www.fanoox.com" if web_site_name == "www.iostream.ir" && platform_name == "www.fanoox.com" { print(web_site_name, platform_name) } else { print("None") } اگر در مثال بالا، هر دو شرط مبنی بر اینکه دو مقدار متغییر تعریف شده باید برابر با مقدار تعیین شده در شرط باشند تا مقادیر چاپ شوند. در غیر اینصورت با خروجی None روبرور خواهیم شد. آپِریِتر || این یکی زیاد گیر نمیده که حالا حتما باید هر دو شرط با هم برقرار باشن! یکی از شرط‌ها در بین چندین شرط که برقرار باشه و به عبارتی نتیجه درست (‌ true ) برگردونه، وارد بدنه‌ی شرطه میشه و دستورات رو اجرا می‌کنه. اگه تمامی شرط‌ها نادرست (‌ false ) بودند، دستورات داخل بدنه اجرا نخواهند شد. به مثال زیر دقت کنید: var web_site_name, platform_name : String web_site_name = "www.iostream.ir" platform_name = "www.fanoox.com" if web_site_name == "www.iostream.ir" || platform_name == "www.fanoox.ir" { print(web_site_name, platform_name) } else { print("None") } در مثال بالا شرط دوم برقرار نیست! چرا که متغییر platform_name با مقدار سمت راست آن برابر نیست. اما از آنجایی که از آپرِیِتر ||‌ استفاده کردیم، پس شرط اول درست بوده و دستورات داخل بدنه‌ی شرط if اجرا می‌شوند. کلمات کلیدی continue,break,fallthrough کلمه‌ی کلید continue اگر بخواهیم در یک حلقه در یک جایی به بعد دستورات اجرا نشوند و مجددا حلقه اجرا شود، از این کلمه‌ی کلید کمک می‌گیرم. به مثال زیر دقت کنید: for index in 0...20 { if index == 5 { continue } print(index) } /* Output the number 0 1 2 3 4 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 */ همان‌طور که مثال بالا مشاهده‌ کردید، در حلقه‌ی for شرط داخل حلقه بر این مبنا بود که اگر متغییر index مساوی مقدار ۵ شد، ادامه‌ی دستورات را ادامه نده ( continue ) و مجدد حلقه را از سر بگیر. بخاطر همین است که عدد ۵ نمایش داده نشده. کلمه‌ی کلید break با این کلمه‌ی کلید به راحتی می‌توانید هر جایی از حلقه که دیگر نیازی نداشتید که حلقه ادامه ندهد، با این کلمه کلید حلقه را متوقف یا به اصطلاح بشکنید!. با این کار دیگر حلقه تکرار نشده و دستورات بعد از حلقه اجرا خواهند شد. به مثال زیر دقت کنید: for index in 0...5 { if index == 2 { break } print(index) } /* Output the number 0 1 */ کلمه‌ی کلید fallthrough شاید در جایی از دستوری شرطی switch لازم داشتید که caseهای بعدی هم اجرا شوند. با این کلمه‌ی کلیدی می‌توانید این کار را انجام دهید. به مثال زیر دقت کنید: let _number : Int8 = 1 switch _number { case 2: print(2) case 1: print(1) fallthrough case 3: print(3) fallthrough default: print("None") } بعد از هر caseی که می‌خواهید اجرا شود باید این کلمه‌ی کلید را قرار دهید. منتظر جلسه‌ی پنجم این دوره‌ی آموزشی باشید.
  9. 2 امتیاز
    معرفی نسخه‌بندی معنایی ویرایش ۲.۰ در دنیای مدیریت نرم‌افزار مکان مخوفی به نام «جهنم وابستگی» (dependency hell) وجود دارد. هر چه سیستم شما بزرگتر باشد و بسته‌های (package) بیشتری با نرم‌افزار شما یکپارچه شده باشند، احتمال بیشتری وجود دارد که روزی خود را دراین گودال ناامیدی بیابید. در سیستم‌هایی با وابستگی‌های زیاد، انتشار بسته‌ی جدید به زودی می‌تواند تبدیل به یک کابوس شود. اگر ویژگی‌های وابستگی‌ها بسیار جزئی‌نگرانه باشد، در خطر قفل نسخه (version lock) خواهید بود (ناتوانی برای بروزرسانی یک بسته، بدون اجبار جهت انتشار نسخه‌های جدید همه‌ی بسته‌های وابسته). اگر وابستگی‌ها بسیار ضعیف مشخص شده باشند، به ناچار زخم بی‌قاعدگی نسخه را خواهید خورد (به فرض سازگاری بیش از حد معقول با نسخه‌های آتی‌تر). جهنم وابستگی آنجایی است که قفل نسخه و یا بی‌قاعدگی نسخه از پیشرفت رو به جلوی آسان و امن پروژه‌ی شما جلوگیری می‌کند. برای پاسخگویی به این مشکل، من یکسری قوانین و پیش‌نیازهای ساده را پیشنهاد میدهم که نحوهٔ تخصیص و افزایش شماره‌های نسخه را دیکته می‌کند. این قوانین برپایه‌ی شیوه‌های موجود رایج و گسترده‌ی در حال استفاده، هم در نرم‌افزارهای متن‌باز و غیر متن‌باز است، اگرچه لزوماً محدود به آن نیست. برای آنکه این سیستم کار کند نخست لازم است یک API عمومی (public) تعریف کنید. این امر ممکن است شامل مستندسازی، یا بوسیله‌ی خود کد مقید شده باشد. صرف نظر از این موضوع، مهم است که این API دقیق و واضح باشد. زمانیکه API عمومی خود را مشخص کردید، تغییرات آن را با افزایش معین شماره‌ی نسخه‌ی خود مرتبط می‌سازید. قالب نسخهای به صورت X.Y.Z را در نظر بگیرید. خطاهایی که تاثیری بر API ندارند، نسخه‌ی وصله (Patch) را افزایش می‌دهند، افزایش یا تغییر API که با نسخه‌های قبلی سازگار است، نسخه‌ی جزئی (Minor) را افزایش می‌دهند، و تغییرات API که با نسخه‌های قبل ناسازگار هستند، نسخه‌ی اصلی (Major) را افزایش می‌دهند. این سیستم را «نسخه‌بندی معنایی» می‌نامیم. بر اساس این طرح، شماره‌های نسخه و روشی که تغییر می‌کنند، معنی و مفهومی را درباره‌ی کد تحت آن نسخه، و آنچه که از یک نسخه تا نسخه‌ای دیگر ویرایش شده است، انتقال می‌دهد. به فرض اینکه نسخه‌ی MAJOR.MINOR.PATCH یا اصلی.جزیی.وصله داده شده است: شماره‌ی نسخه‌ی اصلی (MAJOR) را زمانی افزایش دهید که تغییرات API ناسازگار اعمال کرده‌اید، شماره‌ی نسخه‌ی جزئی (MINOR) را زمانی افزایش دهید که قابلیت‌هایی اضافه کرده‌اید که با نسخه‌های قبل سازگار هستند، شماره‌ی نسخه‌ی وصله (PATCH) را زمانی افزایش دهید که تصحیح خطاهایی (bug) اعمال کرده‌اید که با نسخه‌های قبل سازگار هستند. برچسب‌های اضافی برای پیش‌نشر و ساختن فراداده به صورت پسوندهایی برای قالب MAJOR.MINOR.PATCH فراهم است. ویژگی‌های نسخه‌بندی معنایی (SemVer) کلمات کلیدی «باید»، «نباید»، «نیاز است»، «می‌بایست»، «نمی‌بایست»، «توصیه شده است»، «ممکن است» و «اختیاری» در این مستند می‌بایست بر مبنای آنچه در RFC 2119 تعریف شده است، معنا شوند. نرم‌افزارهایی که از نسخه‌بندی معنایی استفاده می‌کنند باید یک API عمومی اعلام کنند. این API می‌تواند در خود کد اعلام شود، یا به طور واضح در مستندسازی وجود داشته باشد. هر طور که انجام شود، می‌بایست دقیق و جامع باشد. یک شماره‌ی نسخه‌ی عادی باید قالب X.Y.Z را داشته باشه طوری که در آن X ،Y و Z اعداد صحیح غیرمنفی هستند و نباید صفر اضافه (leading zero) داشته باشند. X نسخه‌ی اصلی، Y نسخه جزیی، و Z نسخهٔ وصله است. هر عنصر باید به صورت شمارشی افزایش یابد. به عنوان مثال 1.9.0 -> 1.10.0 -> 1.11.0. زمانی‌که یک بسته‌ی نسخه‌بندی شده منتشر شد، محتوای آن نسخه نباید دستکاری شود. هرگونه تغییری باید به عنوان نسخه‌ی جدید منتشر شود. نسخه‌ی اصلی شمارهٔ صفر (0.y.z) برای توسعه‌های ابتدایی است. هرچیزی در هر زمانی ممکن است تغییر کند. API عمومی نمی‌بایست ماندگار در نظر گرفته شود. نسخهٔ 1.0.0 API عمومی را تعریف می‌کند. روشی که شمارهٔ نسخه‌ی بعد از این انتشار افزوده می‌شود، به این API عمومی و نحوهٔ تغییر آن وابسته است. نسخه‌ی وصله Z (x.y.Z | x > 0) باید در صورتی افزوده شود که تصحیح‌های خطای سازگار با نسخهٔ قبلی معرفی شده باشند. یک تصحیح خطا به عنوان یک تغییر داخلی تعریف می‌شود که رفتارهای نادرست را اصلاح می‌کند. نسخهٔ جزیی Y (x.Y.z | x > 0) باید در صورتی افزوده شود که عملکرد سازگار با نسخه‌های قبل جدیدی به API عمومی معرفی شده باشد. همچنین اگر هرگونه عملکرد API عمومی به عنوان منسوخ‌شده برچسب خورده باشد، این شماره باید افزوده شود. اگر عملکرد جدید یا بهبود قابل توجهی در کدهای داخلی معرفی شده باشد، ممکن است نسخهٔ جزیی افزوده شود. ممکن است که شامل تغییرات سطح وصله هم باشد. زمانیکه نسخه جزیی افزوده شود، نسخهٔ وصله باید به 0 بازنشانده شود. نسخه‌ی اصلی X (X.y.z | X > 0) باید در صورتی افزوده شود که هرگونه تغییرات ناسازگار با نسخه‌های قبل به API عمومی معرفی شده باشد. ممکن است این تغییرات شامل سطوح جزیی و وصله نیز باشد. نسخه‌ی جزئی و وصله زمانیکه نسخه‌ی اصلی افزوده می‌شود باید به 0 بازنشانی شوند. یک نسخه‌ی پیش‌انتشار ممکن است با اضافه کردن یک خط تیره و یک سری شناسه‌هایی که به وسیله‌ی نقطه از هم جدا ‌شده‌اند و بلافاصله به دنبال نسخه‌ی وصله می‌آیند، نشانه‌گذاری شود. شناسه‌ها باید تنها شامل اعداد و حروف الفبای اَسکی (ASCII) و خط تیره [A-Za-z0-9] باشند. شناسه‌ها نباید تهی باشند. شناسه‌های عددی نباید با صفر اضافه آغاز شوند. نسخه‌ی پیش‌انتشار از اولویت پایین‌تری نسبت به نسخه‌ی عادی مرتبط برخوردار است. یک نسخه‌ی پیش‌انتشار حاکی از آن است که نسخه‌ی ناپایدار است و ممکن است نیازمندی‌های سازگاری مورد نظر را آنگونه که در نسخه‌ی عادی مرتبط نشان داده شده است، برآورده نکند. مثال: 1.0.0-alpha, 1.0.0-alpha.1, 1.0.0-0.3.7, 1.0.0-x.7.z.92. متادیتای ساخت (build metadata) ممکن است با افزودن یک علامت جمع (+) و یک سری شناسه‌هایی که به وسیلهٔ نقطه ازهم جدا شده‌اند، و بلافاصله به دنبال نسخه‌ی وصله یا پیش‌انتشار می‌آیند، نشانه‌گذاری شود. شناسه‌ها باید تنها شامل اعداد و حروف الفبای اَسکی (ASCII) و خط تیره [A-Za-z0-9] باشند. شناسه‌ها نباید تهی باشند. متادیتای ساخت می‌بایست در زمان تعیین اولویت نسخه درنظر گرفته نشود. بنابراین دو نسخه که تنها در متادیتای ساخت با یکدیگر متفاوت هستند، اولویت یکسان دارند. مثال: 1.0.0-alpha+001, 1.0.0+20130313144700, 1.0.0-beta+exp.sha.5114f8 اولویت اشاره دارد به اینکه چگونه نسخه‌ها زمانی‌که مرتب شده‌اند با یکدیگر مقایسه می‌شوند. اولویت باید به وسیله‌ی جداسازی نسخه به اصلی، جزیی، وصله و شناسه‌های پیش‌انتشار به همین ترتیب، محاسبه شود (متادیتای ساخت در اولویت نمایان نمی‌شود). اولویت، به وسیلهٔ اولین تفاوت تعیین می‌شود هنگامی که این مشخصه‌ها از چپ به راست مقایسه شوند، بدین صورت: نسخه‌های اصلی، جزیی و وصله همیشه به صورت عددی مقایسه می‌شوند. مثال: 1.0.0 < 2.0.0 < 2.1.0 < 2.1.1. زمانی که اصلی و جزیی و وصله برابر هستند، یک نسخهٔ پیش‌انتشار از اولویت کمتری نسبت به نسخهٔ عادی برخوردار است. مثال: 1.0.0- alpha < 1.0.0 اولویت برای دو نسخه‌ی پیش‌انتشار با نسخه‌ی اصلی، جزیی و وصله‌ی مشابه باید به وسیله‌ی مقایسه‌ی هر مشخصه‌ای که با نقطه جدا شده، از چپ به راست مشخص شود تا زمانی که یک تفاوت به شرح زیر یافت شود: شناسه‌هایی که تنها شامل اعداد صحیح هستند به صورت عددی و شناسه‌هایی که با حروف یا خط‌های تیره به صورت الفبایی به ترتیب ASCII مقایسه می شوند. مشخصه‌های عددی همیشه از اولویت کمتری نسبت به مشخصه‌های غیرعددی برخوردار هستند. مجموعه‌های بزرگتری از بخشهای پیش‌انتشار اولویت بیشتری نسبت به مجموعه‌های کوچکتر دارند، اگر همه مشخصه‌های اولویت برابر باشند. مثال: 1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta < 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0. چرا از نسخه‌بندی معنایی استفاده شود؟ این ایده‌ای جدید یا انقلابی نیست. در واقع، احتمالاً شما چیزی مشابه به این را پیش از این انجام داده‌اید. مشکل اینجاست که «مشابه» به اندازه‌ی کافی خوب نیست. بدون انطباق با نوعی تعریف رسمی، شماره‌های نسخه ضرورتاً برای مدیریت وابستگی (dependency) بلااستفاده هستند. بوسیله‌ی اختصاص اعداد و تعاریف واضح به ایده‌های بالا، برقراری ارتباط میان کاربران نرم‌افزار شما و اهدافتان آسان‌تر می‌شود. به‌مجرد اینکه این اهداف واضح شود، مشخصات وابستگی انعطاف‌پذیر (نه آن‌چنان انعطاف‌پذیر) می‌تواند نهایتاً ایجاد شود. یک مثال ساده می‌تواند نشان دهد که چگونه نسخه‌بندی معنایی می‌تواند جهنم وابستگی را به خاطره‌ای از گذشته تبدیل کند. کتابخانه‌ای به نام «Firetruck» را در نظر بگیرید. این کتابخانه به یک بسته به نام «Ladder» که به صورت معنایی نسخه‌بندی شده، احتیاج دارد. در زمانی که firetruck ساخته شده، Ladder در نسخه‌ی 3.1.0 است، شما می‌توانید وابستگی Ladder را با آسودگی به عنوان بزرگتر یا برابر با 3.1.0 و نه کمتر از 4.0.0 تعیین کنید. شما می‌توانید آن‌ها را در سیستم مدیریت بستهٔ خود منتشر کنید و بدانید که آن‌ها با نرم‌افزار وابسته موجود سازگار هستند. بدون شک به عنوان یک توسعه‌دهنده‌ی مسئولیت‌پذیر شما خواهید خواست که هر بسته همان‌طورکه اعلان شده ارتقاء یابد. دنیای واقعی مکان به هم ریخته ایست، ما جز اینکه هشیار باشیم نمی‌توانیم کاری درباره‌ی آن انجام دهیم. آنچه شما می‌توانید انجام دهید این است که بگذارید نسخه‌بندی معنایی به شما یک راه عاقلانه ارائه دهد، تا بسته‌ها را منتشر کرده و ارتقاء دهد بدون آنکه نسخه‌های جدیدی از بسته‌های مستقل را راه اندازی کند و شما را عذاب نداده، در وقت شما صرفه‌جویی کند.. اگر همه‌ی این‌ها مطلوب به نظر می‌رسد، همه‌ی آنچه شما برای شروع استفاده از نسخه‌بندی معنایی احتیاج دارید این است که اعلام کنید که در حال انجام این کار هستید و از قوانین پیروی کنید. به این وب‌سایت از طریق صفحه README خود لینک بزنید، در نتیجه دیگران دربارهٔ قوانین خواهند دانست و از آن نفع خواهند برد. سوالات متداول چگونه باید با نسخه‌ها در فاز توسعه‌ی ابتدایی 0.y.z کنار بیایم؟ ساده‌ترین کار برای انجام دادن این است که توسعهٔ ابتدایی خود را از انتشار 0.1.0 آغاز کنید و سپس نسخهٔ جزیی را برای هر انتشار آتی افزایش دهید. چگونه بدانم چه زمانی باید 1.0.0 را منتشر کنم؟ اگر نرم‌افزار شما در طول تولید مورد استفاده قرار گرفته است، احتمالاً می‌بایست هم‌اکنون 1.0.0 باشد. اگر یک API ماندگار دارید که کاربران روی آن حساب می‌کنند، شما باید 1.0.0 باشید. اگر در مورد سازگاری با نسخه‌های قبل خیلی نگران هستید، احتمالاً می‌بایست هم‌اکنون 1.0.0 باشید. آیا این روش، توسعه و تکرار سریع را کند نمی کند؟ نسخه‌ی اصلی صفر تماماً در مورد توسعهٔ سریع است. اگر شما API را هر روز تغییر می‌دهید، یا باید هنوز در نسخه‌ی 0.y.z باشید یا در یک شاخه‌ی توسعه‌ی جداگانه که بر نسخه‌ی اصلی بعدی کار می‌کند هستید. اگر حتی کوچکترین تغییرات ناسازگار با نسخه‌های قبل در API عمومی نیازمند یک نسخهٔ اصلی باشد، آیا من خیلی سریع به نسخه 42.0.0 نخواهم رسید؟ این سوال یک توسعه‌دهنده‌ی مسئولیت‌پذیر و آینده‌نگر است. تغییرات ناسازگار نمی‌بایست به راحتی در نرم‌افزاری که کدهای وابسته‌ی زیادی دارد معرفی شود. هزینه‌ای که برای ارتقاء باید متحمل شد می‌تواند قابل توجه باشد. اجبار برای ایجاد نسخه‌های اصلی برای انتشار تغییرات ناسازگار، یعنی شما به تأثیر تغییراتتان فکر خواهید کرد و نرخ هزینه/سود مورد نظر را خواهید سنجید. مستندسازی تمامی API عمومی کار بسیار زیاد می‌برد! این مسئولیت شما به عنوان یک توسعه‌دهنده‌ی حرفه‌ای است تا به طور مناسب نرم‌افزار که می‌بایست توسط دیگران مورد استفاده قرار گیرد را مستندسازی کنید. مدیریت پیچیدگی نرم‌افزار یک بخش فوق‌العاده مهم ازکارآمد نگه‌داشتن پروژه است، و انجام آن سخت است اگر کسی نداند که چگونه نرم‌افزار شما را استفاده کند یا چه متدهایی برای صدا زدن امن است. در دراز مدت، نسخه‌بندی معنایی و پافشاری بر یک API عمومی خوش‌تعریف می‌تواند همه چیز و همه کس را در اجرا کردن راحت در موقعیت مناسبی نگه دارد. چه کار می‌توانم بکنم اگر تصادفاً یک تغییر ناسازگار با نسخه‌های قبل را به عنوان نسخه‌ی جزئی منتشر کردم؟ به مجرد اینکه متوجه این مورد بشوید، تنظیمات نسخه‌بندی معنایی را به هم زده‌اید، مشکل را حل کنید و یک نسخه‌ی جزیی جدید که مشکل را تصحیح کند و سازگاری با نسخه‌های قبل را بازگرداند، منتشر سازید. حتی تحت این شرایط، این پذیرفته شده نیست که انتشارهای نسخه‌بندی شده را دستکاری کنید. اگر مناسب است نسخه‌ی متخلف را مستند‌سازی کنید و کاربران خود را از مشکل مطلع سازید تا آن ها نیز از نسخه‌ی متخلف آگاه باشند. چه کار باید بکنم اگر وابستگی‌های خودم را بدون تغییر دادن API عمومی به‌روزرسانی کردم؟ این مورد تا زمانی که API عمومی را متأثر نسازد سازگار تلقی خواهد شد. نرم‌افزاری که صریحاً به همان وابستگی‌هایی که بسته‌ی شما وابسته است، وابسته باشد، باید مشخصات وابستگی خود را داشته باشد و نویسنده باید هرگونه مغایرت را ذکر کند. تشخیص اینکه آیا تغییر ازنوع دستکاری در سطح جزیی است یا سطح وصله، به این بستگی دارد که آیا شما وابستگی‌های خود را جهت تصحیح یک خطا یا برای یک کاربرد جدید به‌روزرسانی کرده‌اید. من معمولاً کد اضافی برای موارد آتی در نظر می‌گیرم، که بدون شک این موارد افزایش سطح جزیی می‌باشد. چه می شود اگر من بدون اعلام قبلی API عمومی را به صورتی تغییر دهم که با تغییر عدد نسخه سازگار نباشد؟ (یعنی کد به نادرست تغییر اصلی‌ای را در انتشار وصله معرفی می‌کند) از بهترین قضاوت خود استفاده کنید. اگر شما مخاطبان زیادی دارید که به شدت به وسیله‌ی تغییر رفتار به آنچه قبلاً برای API عمومی در نظر گرفته شده، متأثر خواهند شد، پس بهترین کار انجام یک انتشار نسخه‌ی اصلی است، حتی اگر اصلاح اعمال شده مؤکداً یک انتشار وصله محسوب شود. به یاد داشته باشید، نسخه‌بندی معنایی تماماً درباره‌ی انتقال معنا بوسیله چگونگی تغییر عدد نسخه می‌باشد. اگر این تغییرات برای کاربران شما مهم است، از عدد نسخه برای آگاه‌سازی آن‌ها استفاده کنید. چگونه باید با منسوخ کردن عملکرد (deprecating functionality) کنار بیایم؟ منسوخ کردن عملکرد موجود بخشی عادی از توسعه‌ی نرم‌افزار است و معمولاً برای این‌که پیشرفت رو به جلو حاصل شود مورد نیاز است. زمانی‌که بخشی از API عمومی خود را منسوخ می‌کنید، باید دو کار انجام دهید: ۱) مستندسازی خود را به‌روزرسانی کنید تا به کاربر اجازه دهید از تغییرات باخبر شود. ۲) یک انتشار جزیی که در آن قسمت منسوخ شده در جایگاه خود باشد منتشر کنید. قبل از آنکه عملکرد را به طورکامل در یک انتشار اصلی حذف کنید حتماً باید حداقل یک انتشار جزیی که شامل قسمت منسوخ شده است وجود داشته باشد تا کاربران به راحتی بتوانند به API جدید منتقل شوند. آیا SemVer محدودیت اندازه بر روی رشته‌ی نسخه دارد؟ خیر، اما از قضاوت مناسبی استفاده کنید. به عنوان مثال یک نسخه‌ی ۲۵۵ نویسه‌ای احتمالاً مفید نخواهد بود! همچنین، سیستم‌های خاص ممکن است محدودیت‌های خود برای اندازه‌ی رشته اعمال کنند. - منبع
  10. 2 امتیاز
    درود بر شما؛ بله مشکل دارد، همانطوری که خودتان هم گفتید دارید آدرس یک متغیر محلی را از تابع بر می‌گردانید که این اخطار را هم از سمت کامپایلر هنگام کامپایل آن تابع دریافت می‌کنید ‌: $ warning: function returns address of local variable و برنامهٔ شما هم به احتمال زیاد Segmentation Falut داده و از بین می‌رود. برنامهٔ شما ممکن است که خروجی درستی نداشته باشد، چراکه دارید از یک حافظه‌ای داده را می‌خوانید که اصلاً وجود ندارد (حافظه آزاد شده است). در کامپایلر 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; }
  11. 2 امتیاز
    سلام، افزونه‌ی Qt در Visual Studio تنها امکان توسعه‌ی برنامه‌های تحت کیوت رو در محیط ویژوال استودیو می‌دهد (بنابراین هماهنگی کامل با فناوری‌های اختصاصی کیوت را نخواهد داشت). در صورتی که شما کامپایلر و تنظیمات qmake یا cmake را برای پلتفرم‌های مورد نظر به درستی تنظیم کنید می‌تونید خروجی مناسب را تهیه کنید. دقت کنید که برای iOS و Linux شما باید روی پلتفرم‌های مک و لینوکس خروجی بگیرید. برای iOS و macOS بهترین روش همین هست که شما در پلتفرم مربوط به خودشون کامپایل کنید. حتی برای لینوکس هم بهتره از همین روش استفاده کنید (هرچند به کمک روش کراس کامپایل می‌تونید خروجی بگیرید). سعی کنید از استاندارد‌ها و رابط‌های خاص ویندوز استفاده نکنید، سعی کنید استاندارد‌های هر پلتفرم رو برای خودش اعمال و تحت چهارچوب و قوانین کیوت طراحی و توسعه انجام بدین. در این صورت بدون دردسر‌های متداول می‌تونید برنامه‌ی خودتون رو برای پلتفرم مقصد خروجی و اجرا کنید. این بخش هم مقالات و آموزش‌های مناسبی موجود هستند که پیشنهاد می‌کنم بررسی بفرمایید.
  12. 2 امتیاز
    @Alireza4 درود؛ اینکه چه کاری انجام بدهید و به کدام راه برید، تماماً بستگی به خودتان دارد. پیشنهاد می‌کنم که قشنگ درمورد کاری که می‌خواهید انجام بدید تحقیق کنید : - هدفتان از برنامه‌نویسی چیست ؟ - چقدر حوصلهٔ یادگیری مطالب را دارید ؟ - چقد دید سیستمی به برنامه‌نویسی دارید ؟ و ..، این مطلب را حتماً مطالعه کنید : کدام زبان برنامه‌نویسی را انتخاب کنم ؟ ، در این مقاله توضیحات لازم داده شده که بتونید خودتان تصمیم بر انتخاب زبان بگیرید. چرا که باید بدونید «درسته‌که زبان سی‌پلاس‌پلاس قدرت زیادی داره» امّا باید بدونید که هرچیز خوبی بالاخره هزینه‌ای هم داره و یادیگری کار کردن با این زبان به شش‌ماه تموم نمیشه، برای اینکه دراین‌باره هم بیشتر اطلاعات کسب کنید مقالهٔ چرا و چگونه باید ++C را یادبگیریم ؟ ، شاید اصلاً چیزی نبود که شما فکر می‌کردید.
  13. 2 امتیاز
    پردازنده‌ها چگونه طی ۴۰ سال گذشته تغییر کرده‌اند؟ پردازنده‌ها از پیدایش تا‌به‌حال، در‌حال‌پیشرفت بوده‌اند و روز‌به‌روز درکنار قدرتمند‌ترشدن، مصرف انرژی آن‌ها هم بهینه‌سازی شده است. اما این پیشرفت‌ها چقدر بوده و در آینده چگونه خواهد بود؟ وقتی از طرح‌های پیشرفت تکنولوژی، به‌ویژه قانون مور، صحبت به‌میان می‌آید، طرح «۳۵ سال از داده‌های ریزپردازنده‌ها» که آن را ام. هورویتز، اف. لابونت، اُ. شچم، کی. الوکتن، ال. هموند و سی. بَتِن جمع‌آوری کرده‌اند، می‌تواند یکی از طرح‌های مهم باشد. بعد‌ها، سی. مور هم اطلاعاتی به این پروژه اضافه کرد. این طرح را چه با خطوط پیشرفت و چه بدون آن‌ها می‌توان در جاهای مختلفی از اینترنت پیدا کرد؛ هر‌‌چند این طرح فقط تا سال ۲۰۱۰ کامل شده و در چند سال اخیر، کامل نشده است. برای به‌روزکردن داده‌های این طرح که هر‌چند درست‌بودن آن تا سال ۲۰۱۰ مشخص نیست، داده‌هایی از g3data و داده‌های دیگری هم از پردازنده‌های AMD Opteron، پردازنده‌های Intel Xeon، پردازنده‌های Power7+ و Power8 مانند Xeon Phi به این طرح اضافه شدند. جزئیات این داده‌های جدید را به‌صورت خام می‌توانید درون این فایل زیپ ببینید. نتیجه‌ی این طرح عکس زیر است: درادامه، طرح به‌روز‌شده را با طرح اصلی می‌توانید مقایسه کنید. نکته‌ای جالبی که وجود دارد، این است که باتوجه‌به اینکه عملکرد پردازش تک‌هسته‌ای ازنظر کمّیّت مهم است، این مقدار پیوسته در‌حال‌پیشرفت بوده است. این افزایش نتیجه‌ی مدیریت انرژی هوشمندانه و تنظیم دینامیک فرکانس کلاک (توربو) بوده است. در آینده، چه تغییراتی به وجود خواهد آمد؟ احتمالا فرکانس و انرژی مصرفی دستخوش تغییرات زیادی قرار نخواهند گرفت. بهبود بیشتر در ساختار کلاک ممکن است باعث افزایش تدریجی عملکرد تک‌هسته‌ای پردازنده‌ها شود که البته نمی‌توان انتظار تغییر بزرگی داشت. دو نمونه از کمّیّت‌های مهم، تعداد ترازیستور‌ها و تعداد هسته‌ها هستند. تا چه زمانی قانون مور ادامه خواهد داشت؟ این احتمال وجود دارد که در آینده‌ای نزدیک، افزایشی در تعداد هسته‌ها را شاهد خواهیم بود؛ اما شاید تعداد ترانزیستور‌ها تغییری اساسی نکنند. در‌حال‌حاضر، Haswell Xeon در صدر فهرست پردازنده‌ها هستند که ۱۸ هسته‌ی پردازشی دارند. به‌هرحال با وجود این پردازنده‌ها، قانون امدال ما‌ را به‌ دنبال‌کردن همین الگوریتم ملزم خواهد کرد. پردازندهی Knight Landing Xeon Phis که به‌زودی رونمایی خواهد شد، ۷۲ هسته دارد که بیش از ۶۱ هسته بیشتر از نسل کنونی‌اش خواهد داشت. از دیدگاه الگوریتم‌ها، واقعا مهم نیست پردارنده با ۶۱ یا ۷۲ هسته کار می‌کند یا خیر؛ بلکه در هر دو مورد، الگوریتم‌هایی موازی موردنیاز هستند. در این مرحله، باید خوشحال باشیم که در‌حال‌حاضر، توانسته‌ایم با یادگیری برنامه‌ریزی GPU‌ها این الگوریتم‌ها را طراحی و اجرا کنیم. به‌روزرسانی ۲۰۱۸ دو سال داده‌ی بیشتر به‌نظر مهم نیست، هرچند به‌نظر می‌رسد قانون مور در‌حال‌ کم‌رنگ‌شدن است. یکی از موضوعاتی که باید به آن اشاره کرد، این است که اینتل دیگر تعداد ترانزیستور‌های پردازنده‌های خود را اعلام نمی‌کند. همچنین، تعدادی از پردازنده‌های این شرکت زمان زیادی بعد از موعد مقرر معرفی شدند. مدل Tick-Tock هم اصلاح شده است. با داده‌هایی از تعداد ترانزیستور‌ها که از AMD Epyc و IBM Power 9 به‌دست‌آمده طرح را به‌صورت زیر به‌روزرسانی کرده‌اند: واضح است تعداد ترانزیستور‌ها به‌صورت نموداری نمایی رو‌به‌پیشرفت بوده است. تا‌به‌امروز، پردازنده‌ی AMD Epyc با ۱۹،۰۰۰،۰۰۰،۰۰۰ ترانزیستور که به‌صورت عمومی اعلام شده، بیشترین تعداد ترانزیستور را در میان پردازنده‌ها دارد. برای مقایسه باید گفت تراشه‌ی پاسکال Nvidia GP100 درحدود ۱۵،۰۰۰،۰۰۰،۰۰۰ ترانزیستور دارد. با درنظرگرفتن این تعداد، این ارقام باهم سازگار هستند و جای شکی در تعداد ترانزیستور‌ها وجود ندارد.به‌زودی، با معرفی نود‌های پردازشی ۱۰ نانومتری منطقی است که احتمال دهیم تا چند سال آینده، منحنی نمایی و رو‌به‌رشد تعداد ترانزیستور‌ها پیشرفت خود را حفظ کند. تعداد ترانزیستور بیشتر موجب افزایش تعداد هسته‌ها می‌شود. این درحالی است که پیشرفتی که در SpecINT برای محاسبه عملکرد تک‌هسته‌ای قابل مشاهده‌است، مستقیما نتیجه‌ی استفاده از کامپایلر‌های Auto-Vectorization و Auto-Parallelization است.
  14. 2 امتیاز
    سلام و درود خدمت دوستان عزیز، همانطور که می‌دانید مهمترین و شاید بزرگترین سوال در حوزه‌ی برنامه‌نویسی این است که من باید کدام زبان برنامه‌نویسی را انتخاب کنم؟! واقعیت امر این است که این سوال همیشه از سمت علاقه‌مندان مطرح شده است اما هیچگاه یک پاسخ اساسی در مورد آن ارائه نشده است. البته اساتید و برنامه‌نویسان حرفه‌ای به خوبی می‌دانند که زبان‌های برنامه‌نویسی به عنوان ابزار‌های کمک کار ما کاربرد دارند و به هیچ عنوان نمی‌توان یک زبان را به عنوان اولین و آخرین انتخاب در نظر گرفت، اما شناخت در مورد آن‌ها کمک بسیاری در انتخاب ابزار‌های مناسب خواهد کرد. در این پُست من قصد دارم در رابطه با انتخاب یک زبان برنامه‌نویسی بر اساس نیاز و علایق صحبت کنم تا شما عزیزان بتوانید به یک نتیجه‌ی مطلوب برسید. بنابراین، قبل از هر چیز این بسیار مهم است که بدانیم یک زبان برنامه‌نویسی چیست! و چرا باید از آن استفاده کنیم؟! اجازه دهید نگاهی به دلیل استفاده از زبان برنامه‌نویسی داشته باشیم، چرا از زبان برنامه‌نویسی استفاده می‌کنیم؟ به برقراری ارتباط با یکدیگر فکر کنید، انسان برای برقراری ارتباط با هم‌نوعان نیاز به ابزاری به نام زبان دارد که عناصر اساسی آن حروف است. برای مثال حروف خ-ا-ن-ه با ترکیب شدن به خانه تبدیل شده و شما می‌توانید آن را درک کنید و این کدی است که شما توسط آن با جهان بیرون خود ارتباط برقرار می‌کنید. ممکن است کد‌های شما توسط یک زبان دیگر مانند زبان انگلیسی ساخته شود، برای مثال h-o-m-e حرفی است که که نتیجه‌ی آن Home خواهد بود. در کشور ما معمولاً زبان مادری هریک از ما فارسی، ترکی (آذربایجانی)، عربی، کردی، لُری و دیگر موارد هستند که به صورت بومی آن را فرا می‌گیریم و با تسلط بسیاری از آن استفاده کرده و منظور هم‌نوعان خود را درک می‌کنیم. در بحث کامپیوتر، استفاده از زبان انسانی تا حدی کاربرد دارد که فقط خود انسان آن را درک خواهد کرد نه ماشین! چرا که زبان بومی و اصلی کامپیوتر (ماشین) ۰ و ۱ است نه کاراکتر و حرف! ماشین‌ها برای برقراری ارتباط و درک منظور انسان از واحد ۰ و ۱ استفاده می‌کنند که مجموعه‌ای از آن‌ها به عنوان دستورالعمل‌های مشخصی برای کامپیوتر قابل درک است. مغز کامپیوتر یعنی واحد پردازشگر مرکزی (CPU) به عنوان پردازنده‌ی مرکزی تمامی داده‌های شما را در قالب ۰ و ۱ شناسایی می‌کند و آن‌ها را درک خواهد کرد. بنابراین زبان بومی ماشین بر خلاف انتظار برای انسان بسیار دشوار است و اگر به فکر این باشید که بخواهید از طریق آن با کامپیوتر ارتباط برقرار کنید شما یک دیوانه‌ی تمام عیار بشمار خواهید آمد! اجازه دهید منظورم را ساده‌تر کنم، کامپیوتر منظور شما را از home درک نخواهد کرد! اما اگر به آن بگویید 01101000 01101111 01101101 01100101 مسلماً خواهد فهمید که منظور شما از آن یعنی home است! حالا اگر منظور شما سلام دنیا باشد باید به کامپیوتر بگویید 01101000 01100101 01101100 01101100 01101111 00100000 01110111 01101111 01110010 01101100 01100100 و همینطور برای برقراری ارتباط بیشتر باید هزاران، میلیون‌ها و میلیارد‌‌ها ۰ و ۱ را با اصول زبان ماشین در کنار هم قرار دهید تا شاید بتوانید یک دستورالعمل ساده برای انجام یک کار را به آن انتقال دهید! احمقانست نه؟! وقت و زمان برای ما انسان‌ها بسیار با ارزش است و مسلماً به هدر دادن آن به این روش هرچند دانش بسیار بالایی از مهندسی کامپیوتر می‌طلبد اما حتی اگر شما یک دانشمند هم باشید بکار گیری این روش دیوانگی محض است! ما که کامپیوتر نیستیم! ما انسانیم ساختار کامپیوتر بسیار شبیه به ساختار انسان است، همانطور که خالق انسان، خداوند یکتا او را آفرید به آن نیز هوش و قدرتِ تفکر داد تا بتواند بر اساس آن رشد کرده و در مسیر پیشرفت قدم بردارد، انسان نیز از دانسته‌های خود برای ساخته‌هایش استفاده می‌کند. کامپیوتر‌ها به عنوان ابزار‌های ساخت دست بشر دارای ساختار بسیار ساده ولی در عین حال بسیار پیچیده هستند که انسان برای برنامه‌ریزی آن نیاز به ابزار‌هایی دارد (ابزار‌هایی برای ایجاد دستورات قابل درک برای ماشین). ابزار‌های برنامه‌ریزی برای کامپیوتر همانطور که اشاره شد، کامپیوتر‌ها هیچ درکی از کد‌هایی که انسان می‌نویسد ندارند! بنابراین ما نیاز به ابزاری داریم تا منظور خود را برای درک کامپیوتر ارائه دهیم. حال آن ابزار می‌تواند یک مفسر (Interpreter) باشد یا یک کامپایلر (Compiler) ! هر دوی این ابزار‌ها وظیفه‌ی دریافت زبان سطح بالا (نزدیک به زبان انسان) و تبدیل (ترجمه‌ی آن) به زبان ماشین است. با تفاوت اینکه مفسر‌ها کد‌های نوشته شده را خط به خط تفسیر کرده و آن‌ها را برای پردازنده اجرا می‌کند، در حالی که کامپایلر تمامی کد‌ها را به شیء و هر شیء را به کد باینری یکجا ترجمه کرده و هرجا که نیاز بود آن‌‌ها توسط پردازنده اجرا می‌شوند. به بیان ساده‌تر فرض کنید قرار است به زبان روسی صحبت کنید، شما دو روش خواهید داشت: صحبت کردن به زبان روسی به صورت مستقیم استخدام یک مترجم، صحبت با مترجم و ترجمه‌ی گفته‌های شما توسط مترجم به طرف مقابل برخی از مزایا و معایب کامپایلر و مفسر نسبت به یکدیگر نکته ۱: مفسر‌ها کد‌های نوشته شده را به صورت خط به خط تفسیر و ترجمه می‌کند اما کامپایلر‌ها آن‌ها را یکجا ترجمه می‌کند که دارای یک خروجی مانند یک فایل اجرایی است. نکته ۲: برنامه‌ی تولید شده تحت کامپایلر توسط سخت افزار (ماشین واقعی) اجرا می‌شود در صورتی که برنامه‌ی تولید شده با مفسر توسط نرم‌افزار (ماشین مجازی) اجرا می‌شود. نکته ۳: کامپایلر‌ها عملیات بهینه‌سازی یا همان (Optimization) را در آخرین مرحله از کامپایل (ترجمه) انجام می‌دهند، در صورتی که مفسر‌ها عملیات بهینه سازی را در زمان تبدیل انجام می‌دهند. نکته ۴: سرعت اجرای کد‌های کامپایل شده بسیار بیشتر از کد‌های تفسیر شده است. برای مثال اگر حلقه‌ای را در نظر داشته باشید که قرار است ۱۰ بار اجرا شود، آن حلقه در حالت مفسر ۱۰ بار تفسیر شده و ۱۰ بار توسط پردازنده اجرا خواهد شد! در حالی که در حال کامپایل شده حلقه یک بار ترجمه می‌شود و نتیجه‌ی آن یک بار توسط پردازنده در زمان نیاز اجرا می‌شود! این بسیار مهم است و در پردازش‌های بسیار بزرگ سرعت برنامه‌های کامپایل شده به شدت بالاتر از تفسیر شده‌ها است. نکته ۵: کد‌های تولید شده توسط مفسر سطح بالاتری نسبت به کد‌های تولید شده توسط کامپایلر دارند در واقع آن‌ها تقریباً قابل خواندن هستند اما کد‌های تولید شده توسط کامپایلر غیر قابل خواندن است. نکته ۶: امنیت برنامه‌های کامپایل شده و همچنین دسترسی به منابع کد آن‌ها از امنیت بیشتری نسبت به برنامه‌های تحت مفسر دارند. نکته ۷: برنامه‌های تفسیر شده وابستگی خاصی به سیستم‌عامل ندارند و در هر جایی که برنامه‌ی تفسیر کننده موجود باشد اجرا خواهند شد، در صورتی که برنامه‌های کامپایل شده برای هر نوع سیستم‌عامل متفاوت باید مجدداً کامپایل شود که البته برای اجرای آن نیازی به نصب بودن کامپایلر بر روی سیستم‌عامل نیست. نکته ۸: کامپایلر‌ کد برنامه را به صورت کامل به کُد ماشین ترجمه می‌کند، بنابراین زمان اجرای آن بسیار کم تر است و انتخاب بسیار خوبی برای دوست‌داران سرعت است. نکته ۹: استفاده از زبان‌های مفسری برای توسعه‌دهندگان مبتدی آسانتر از نوع کامپایلری می‌باشد بنابراین یادگیری و استفاده از این نوع زبان‌ها نسبتاً سریعتر و راحت‌تر از نوع کامپایلری است. فرایند توسعه‌ی نرم‌افزار در این فرایند کامپایلر برنامه را می‌سازد سپس همه دستورات زبان را از نظر صحت تجزیه و تحلیل می‌کند و اگر دستوری غلط باشد، اخطار می‌دهد. در صورتی که خطایی وجود نداشته باشد همه‌ی کد‌ها را به کد ماشین تبدیل می‌کند که در نهایت فایل‌های مختلفی را به برنامه اجرایی اضافه می‌کند و در نهایت برنامه را اجرا می‌کند. در حالی که مفسر برنامه را می‌سازد اما، فرایند افزودن فایل اجرایی به برنامه یا تولید کد‌های ماشین وجود ندارد بلکه دستورات کد منبع خط به خط در حین زمان اجرا یا به اصطلاح Run-time اجرا می‌کند. دسته‌بندی زبان‌های برنامه‌نویسی زبان‌های مفسری: Perl ,Php, Ruby, Python, JavaScript, Forth, JavaScript زبان‌های کامپایلری: C, C++, Clean, Go, Fortran, Haskell, Java, C#, Objective-C, Swift, Rust, D, Delphi, Scala کدام زبان در چه حوزه‌ای کاربرد دارد؟ با توجه به تعاریف بالا نوبت آن رسیده است تا زبان برنامه‌نویسی مورد نظر خود را بر اساس نیاز و قابلیت‌هایی که آن در اختیار توسعه‌دهنده قرار می‌دهد انتخاب کرد. حوزه‌های کاربردی زبان‌های برنامه‌نویسی متناسب با کاربرد و رسالت آن‌ها مشخص می‌شود، به طور کلی زبان‌های برنامه‌نویسی را بهتر است به دو دسته‌ی اصلی و فرعی جدا کنیم. در دسته‌ی اصلی زبان‌هایی که پایه و اساس کتابخانه‌ها، نرم‌افزار‌های عظیم، انجین‌ها و همچنین خود زبان‌های برنامه‌نویسی می‌باشند را زبان مادر و اصلی و تمامی زبان‌هایی که به عنوانی جهتِ مکمل سازی و یا محصول نوع سوم برای اهداف تجاری ساخته شده‌اند را فرعی می‌گوییم. زبان‌های اصلی و مادر: C و ++C زبان‌های اصلی و فرعی: Python, Java, Delphi, C#, Swift, Objective-C, Php, JavaScript زبان‌های مکمل رابط کاربری: JavaScript, CSS, Xaml, Xhtml, Html, QML درنظر داشته باشید کتابخانه‌ها و برنامه‌های اساسی و پایه که بخش اعظمی از آن‌ها توسط زبان‌های سی++ و سی نوشته می‌شوند در صورت نیاز برای زبان‌های دیگر نیز قابل استفاده هستند. به عنوان مثال سیستم‌عامل‌ها، نرم‌افزار‌های عظیم، انجین‌های بازی‌سازی، کتابخانه‌های پرکاربرد و مهم همه‌ی آن‌ها توسط زبان‌های اصلی توسعه یافته‌اند اما در صورت نیاز می‌تواند از کتابخانه‌های نوشته شده توسط زبان‌های اصلی در زبان‌های فرعی نیز استفاده کرد. شاید اینطور به نظر برسد که اگر با زبان‌های اصلی هر کاری می‌توان انجام داد، پس چرا زبان‌های دیگر را مورد استفاده قرار می‌دهیم؟! جواب سوال این است که زبان‌های اصلی و مهم نیاز به دانش بسیار از لحاظ معماری سیستم‌عامل، کامپایلر و دیگر شاخه‌های علوم کامپیوتر هستند و نحوِ کُد‌نویسی در آن‌ها نسبت به زبان‌های دیگر مانند جاوا، پایتون، سی‌شارپ و غیره دشوار‌تر است. بنابراین ممکن است انتخاب اول برنامه‌نویسان مبتدی نباشند اما کاربرد آن‌ها جنریک (عمومی) است. اشاره به کاربرد زبان‌های محبوب در حوزه‌های مختلف: توسعه‌ی وب‌سایت: C++, Java, Php, JavaScript, C#, Ruby, Python توسعه‌ی نرم‌افزار‌های موبایل: , C++, Java, C#, Objective-C, Swift, JavaScript, Kotlin توسعه‌ی نرم‌افزار‌های دسکتاپ: C/C++, Java, Delphi, VB.Net, C#, JavaScript, Objective-C توسعه‌ی نرم‌افزار‌های اِمبِد: C/C++, Python توسعه‌‌ی بازی‌های کامپیوتری: ++C و #C توسعه‌ی هوش مصنوعی: C++,Python, R, Prolog, Java, Haskell, AIML توسعه‌ی رابط‌کاربری: JavaScript, QML, XAML نکته‌ی قابل توجهی از کاربرد زبان‌های اصلی در این است که خود آن‌ها وابسته‌ی زبان برنامه‌نویسی و محدود بر یک حوزه نیستند و به اصطلاح زبان مادر بشمار می‌آیند که و در تمامی حوزه‌ها کاربرد دارند. کاربرد در صنایع و حوزه‌های مختلف بر اساس ویژگی‌هایی که یک زبان برنامه‌نویسی ارائه می‌دهد بسیار مهم است. برای مثال Python, R, Prolog و غیره در حوزه‌ی هوش مصنوعی و بیگ دیتا بسیار ساده‌تر به کمک توسعه دهندگان می‌آید. در توسعه‌ی وب‌سایت زبان‌های برنامه‌نویسی Node.JS, Php, C#, Asp.Net محبوبیت بیشتری دارند. اما می‌توان با توجه به این پست وب‌سایت‌های بسیار سریع و بهینه‌ای را توسعه داد که بی شک نیاز به دانش بسیار بالایی دارد و بهتر است در اهداف خاص از آن استفاده شود. در حوزه‌ی موبایل‌ در پلتفرم iOS دو زبان Swift و Objective-C به عنوان زبان اصلی پلتفرم‌های iOS, tvOS و watchOS به شمار می‌آیند. در حوزه‌ی اندروید (Android) زبان‌های Java و Kotlin به عنوان انتخاب‌های اول توسعه‌دهندگان مطرح می‌شند در صورتی که بسیاری از کتابخانه‌های اندروید تحت C و ++C توسعه یافته و حتی می‌تواند با استفاده از ++C اپلیکیشن‌ و بازی‌های بسیار سریعتری را تولید کرد. در حوزه‌های صنایع بازی‌سازی زبان‌هایی مانند #C نیز کاربرد دارند، اما ترجیح اول و اصلی در این حوزه بکارگیری ++C است چرا که هیچ زبانی به جز آن نهایت سرعت را ارائه نخواهد داد. آمار‌ها و محبوبیت‌ها سالانه طبق گزارش بسیاری از مراجع نمودار‌ها و آمار‌هایی در رابطه با ایندکس شدن زبان‌های برنامه‌نویسی ارائه می‌شود که نمونه‌ای از آن‌ها TIOBE است. متاسفانه باید گفت مقایسه‌ی چنین مراجع بر اساس ویژگی‌هایی که در بالا توضیح دادیم صورت نمی‌گیرد و صرفاً بر اساس محبوبیت بین کاربران گزارش داده می‌شوند. برتری زبان نسب به زبان دیگر بر اساس چنین آمار‌هایی اشتباه بوده و توسط آن نمی‌توان یک زبان را به عنوان انتخاب اول در نظر گرفت. همچنین اگر دقت کنید مقایسه‌ی زبان‌های برنامه‌نویسی اسکریپتی با کامپایلری و همچنین زبان‌هایی مانند SQL در بین آن‌ها وجود دارد که از لحاظ منطقی درست نیست چرا که کاربرد زبان‌ها با یکدیگر متفاوت بوده و ملاک آماری این مراجع فقط استقبال کاربران است. تعاریف و هِدایت‌های اشتباه به سمت یک زبان برنامه‌نویسی متاسفانه مشاهده می‌شود که در بسیاری از گروه‌ها و سایت‌های برنامه‌نویسی چندین زبان برنامه‌نویسی را به عنوان بهترین انتخاب معرفی می‌کنند و دلیل انتخاب آن‌ها را مشاهده‌ی رتبه‌های آن بر اساس ایندکس‌های برخی از مراجع و یا طرفداری بعضی از شرکت‌ها و تعصبات بی هدف است! باید در نظر داشته باشید قدرت و ویژگی‌های یک زبان ربطی به محبوبیت آن ندارد. اگر احساس می‌کنید شرکت‌ها تقاضای متخصص زبان برنامه‌نویسی خاصی را دارد که تکرار می‌شود به آن معنی نیست که زبان‌های برنامه‌نویسی دیگر در حال منسوخ شدن یا کنار گذاشتن هستند. ارزش زبان ملاک برتری آن است نه محبوبیتش! به عنوان مثال اگر JavaScript رتبه‌ی اول از نظر محبوبیت را دارد به آن معنا نیست که Php در حال منسوخ شدن است! هر زبانی کاربرد خودش را نسبت به اهداف و ویژگی‌های خود دارد. آیا زبان ماشین منسوخ شده است؟! خیر! این چه سوالیه!!؟ چنین افکار بیهوده را از ذهن خود بیرون بریزید! تمامی زبان‌های کامپایلری در نهایت کد‌هایشان توسط کامپایلر به زبان ماشین یعنی assembly تبدیل می‌کنند. مثال زیر کد ++C است: int main() { } خروجی آن به زبان ماشین (Assembly) در کامپایلر GCC به صورت زیر خواهد بود: main: push rbp mov rbp, rsp mov eax, 0 pop rbp ret انتخاب چند-سکویی پیشنهاد می‌شود یا خیر؟ لازم بذکر است که بدانید، ابزار‌های چند-سکوی بسیاری وجود دارند که به شما اجازه می‌دهند بدون داشتن دانش آنچنانی در رابطه با زبان‌های برنامه‌نویسی متعددِ مخصوص سکو‌های هدف محصول خود را توسعه دهید. برخی از آن‌ها عبارتند از Xamarin و یا React Native که متاسفانه به دلیل ساختار نامطلوب تبدیل کد‌های نوشته شده نتیجه‌ی نهایی آن‌ها آنچنان خوب مانند محصولات واقعی زبان بومی نیستند چرا که کد‌های آن‌ مستقم به زبان ماشین ترجمه نمی‌شوند. اما این بسیار مهم است که بدانید ابزار‌های بومی چند-سکویی واقعی انتخاب بهتری برای این امر بشمار می‌آیند که معروفترین آن‌ها Qt است که به صورت بومی بدون اُفت کیفیت محصول نهایی به شما اجازه‌ی توسعه محصول در سکو‌های مختلف را می‌دهد که مسلماً دانش بسیار بالایی از سی++ را می‌طلبد. در نتیجه اگر به دنبال محصول با کیفیت در حوزه‌ی چند-سکویی هستید باید دانش بالایی از ++C داشته باشید. نکته: در نظر داشته باشید زبان‌های کامپایلری خود به دو دسته نیز تقسیم می‌شوند که برخی از آن‌ها به صورت مستقیم کد‌های نوشته شده را به کد ماشین ترجمه می‌کنند و برخی از آن‌ها کد نوشته شده را به یک زبان میانی تبدیل و سپس آن را توسط برنامه‌ی مجازی برای ماشین برنامه‌ریزی می‌نمایند. بهتر است توجه داشته آن‌ها مزایا و معایبی نیز خواهند داشت. زبان‌های کامپایلری در دو دسته‌‌ی بومی (Native) و مجازی (Virtual) کامپایل از نوع بومی روشی است که کد‌های نوشته شده‌ را به صورت مستقیم به کُد ماشین ترجمه می‌کند. کامپایل از نوع مجازی روشی است که کد‌های نوشته شده‌ را ابتدا به کُدمیانی (کد‌مشترک یا همان بایت کُد - Byte Code) در جاوا و زبان میانی (CIL) در Net. تبدیل می‌کند که خودِ آن شبیه به کُد ماشین است. در این فرایند کد مربوطه توسط کامپایلر مخصوص یعنی JIT (کامپایلری از نوع Just-In-Time) در زمان اجرا توسط سیستم‌عامل، به دستورالعمل‌های قابل فهم برای پردازنده‌ تفسیر و اجرا می‌شود (که این فرایند شبیه به فرایند عملکرد اجرایی مفسر‌ها است). زبان‌های بومی (زبان‌هایی که کد‌ آن‌ها به کد ماشین به صورت مستقیم توسط کامپایلر قبل از اجرای آن‌ها توسط سیستم‌عامل، ترجمه می‌شوند که به اصطلاح ahead-of-time (جلوتر از زمان) یا همان AOT نام دارد) مانند: C, C++, Rust, Haskell, Clean, Swift, Go, Fortran, D زبان‌های مجازی (زبان‌هایی که کد آن‌ها توسط یک رابط میانی به زبان مشترک ترجمه می‌شود) : Java و #C مزایا و معایب زبان‌های کامپایلری از نوع کلاس بومی (Native) از سرعت بسیار بالایی برخوردار هستند (دلیل آن ترجمه‌ی مستقیم کد‌ها به کد ماشین است) در مقابل بزرگترین مزیتی که زبان‌های نوع کلاس مجازی (Byte Code) دارند به خاطر وجود یک برنامه‌ی واسط جهت شبیه‌سازی کد‌های ترجمه شده به کد قابل فهم برای پردازنده، اجرا شدن آن‌ها در هر پلتفرم بدون کامپایل مجدد امکان پذیر است که البته این ویژگی خود نیازمند نصب بودن JVM بر روی پلتفرم مربوطه می‌باشد. در نوع بومی برای اجرا در هر پلتفرم لازم است سورس کد‌ها را برای پلتفرم مقصد کامپایل کنید که نیازی به وجود ماشین مجازی مانند JVM یا برنامه‌ی خاصی ندارد. سریع‌ترین زبان برنامه‌نویسی کدام است؟ شاید پاسخ به این سوال به گونه‌ای تعصبی به نظر برسد، اما واقعیت این است که باید حقیقت را پذیرفت! با توجه به دلایلی که به نوع زبان‌های کامپایلری آورده شده است مشخص است که سریع‌ترین نوع زبان‌های برنامه‌نویسی باید در دسته‌ی شاخه‌ی کامپایلری و کلاس Native قرار گرفته باشند چرا که در این مبحث زبان‌ها کامپایلری (مجازی) و مفسری حرفی برای گفتن ندارند. جهت تثبیت آن مستنداتی از بنچ‌مارک‌های رسمی از شرایط خاص آورده شده است که به صورت زیر آن‌ها را می‌توانید بررسی کنید: مقایسه‌ی سریعترین عملکرد بین ++C و C# .Net Core مقایسه‌ی سریعترین عملکرد بین ++C و C مقایسه‌ی سریعترین عملکرد بین ++C و Java مقایسه‌ی سریعترین عملکرد بین ++C و Rust مقایسه‌ی سریعترین عملکرد بین ++C و Go مقایسه‌ی سریعترین عملکرد بین ++C و JavaScript مقایسه‌ی سریعترین عملکرد بین ++C و Python حقیقت این است ++C در بدترین حالت ممکن بدون بهینه‌سازی کد‌ها و فلگ‌های خاص حداقل ۲ تا ۴ برابر سریعتر از زبان‌های کامپایلری دیگر است! تلخترین حقیقت نیز این خواهد بود که ++C حداقل ۱۰۰ تا ۲۰۰ برابر سریع‌تر از زبان‌های مفسری است! با توجه به تجربیات شخصی در صورتی که نوع کامپایلر Clang باشد سرعت کد‌ها به چند برابر از این نیز خواهد رسید! همچنین باید در نظر بگیرید اگر کد‌های شما خارج از اصول استاندارد زبان باشد ممکن است نتایج آن به تساوی و حتی پایینترین حالت ممکن برسد. سخن آخر، برای انتخاب زبان برنامه‌نویسی و به دست آوردن مهارت در آن و در نهایت تبدیل دانش به یک محصول نرم‌افزاری، بهتر است بر اساس نوع (کامپایلری یا مفسری بودن)، اهمیت سرعت، ویژگی‌های آن و کاربردش در حوزه‌های مختلف تصمیم بگیرید نه بر اساس تعصب و علاقه. دقت کنید که زبان‌های برنامه‌نویسی ابزار‌های برنامه‌نویسی بوده و هرچقدر جعبه ابزار شما کامل باشد توانایی و مهارت شما در توسعه‌ی حوزه‌های مختلف بیشتر خواهد بود. در صورتی که می‌خواهید در رابطه با انواع روش‌های کامپایل و تفاوت‌های کامپایل Native، Cross Compile و JIT آشنا شوید، پیشنها می‌شود مقاله زیر را مطالعه فرمایید.
  15. 1 امتیاز
    باید متغیر را به‌صورت unsubstituted به List ارسال کنیم تا مقدار درست را برایمان برگرداند.
  16. 1 امتیاز
    مهندس جان بزرگواری کردید با تشکر
  17. 1 امتیاز
    آموزش زبان برنامه‌نویسی سوئیفت - جلسه اول مواردی که در این جلسه یاد خواهید گرفت: مقدمه زبان برنامه‌نویسی سوئیفت ، نوشتن اولین دستور و معرفی متغییر‌ها با سلام و عرض ادب خدمت شما دوستان عزیز و همراهان خوب همیشگی وب‌سایت آیوٌ اِسترِیم. در خدمت شما هستم با یک دوره‌ی جذاب برنامه‌نویسی به زبان سوئیفت! می‌دونم که علاقه‌مندان زیادی به توسعه‌ی محصولات برنامه برای محصولات شرکت اَپل دارن و از این رو با مشکلاتی هم روبرو هستند که یکیش همین نبود آموزش کامل و به بیانی ساده هستش! مورد دومی هم که خیلی تابلو هستش، همین تَحریمه که به جز اینکه دست قِشر کم‌درآمد جامعه رو بسته شامل تحریم‌های دیگه هم هست. و حالا خیلی‌ها بخاطر علاقه به یادگیری نمی‌تونن محصولات اَپل رو خریداری کنن و شروع کنن به توسعه‌ی محصولات نرم‌افزاری شگفت‌اَنگیز! از این رو تنها یک راه وجود داره اونم استفاده از نسخه‌ی هک‌شده‌ی سیستم عامل مَک هستش که به شما امکان استفاده از امکانات یک سیستم‌عامل مَک واقعی رو میده! البته هدف بنده این نیست که بگم استفاده از این روش خوبه! بلکه برای آن دسته از عزیزانی که توانایی خریدن مَک‌بوک و یا سایر محصولات اَپل رو ندارن گفتم وگرنه اگه توانایی خرید دارید که بهترین راهش همینه که بخرید و لذت یک سیستم‌عامل متفاوت و جدید رو داشته باشید :)). خُب،‌ بریم سر اصل مطلب! اینکه در این دوره‌ی آموزش چه چیز‌هایی رو یاد می‌گیرد،‌ فقط و فقط سه چیز هست؛ مقدمات یادگیری Syntax ( سِینتَکس) زبان و کدنویسی مقدماتی یادگیری ‌رابط‌کاربری ( User Interface ) ایجاد یک پروژه‌ی ساده ماشین‌حساب و بعد از این مباحث هم کُلیت کار دستتون میاد و به راحتی ‌می‌تونید از منابعی مُعتبر،‌ دانش و مهارت خودتون رو بالا ببرید. زبان برنامه‌نویسی سوئیفت ( Swift ) چیست ؟ سوئیفت یک زبان‌ برنامه‌نویسی از نوع کامپایلری برای توسعه محصولات نرم‌افزاری macOS , iOS , watchOS و tvOS که توسط شرکت اَپل ساخته شده است. قبل از این از زبان برنامه‌نویسی Objective-C برای توسعه محصولات برای موارد ذِکر شده استفاده می‌شد که بعد از آن این زبان جایش را به سوئیفت داد اما همچنان از Objective-C هم استفاده می‌شود. هدف در اینجا آموزش زبان است و شما می‌توانید برای توضیحات بیشتر به این اینجا مراجعه کنید. شروع کد‌نویسی برای شروع کدنویسی به زبان‌برنامه‌نویسی سوئیفت می‌تونید از یک برنامه‌ موبایل هم حتی استفاده کنید! البته تنها در بخش مقدماتی. نام این نرم‌افزار موبایلی Sedona Swift Compiler است که می‌تونید از فروشگاه Play دانلود و نصب کنید. یا از نرم‌افزار‌ی ساده بر روی ویندوز خود کُد‌نویسی را شروع کنید که هم‌ این‌کار هم برای لینوکس صِدق می‌کند که با نصب یک بسته می‌توانید در لینوکس هم کُد‌نویسی با این زبان شیرین را شروع کنید. یا در نهایت اگر مَک‌بوک دارید که چه بهتر و اگر ندارید از نسخه‌ی هک‌شده‌ی آن استفاده کنید که عرض کردم در موقعی که واقعا چاره‌ای ندارید!. اولین چیز در هر زبان برنامه‌نویسی که آموزش داده می‌شود؛ هِلوُ وُرلد (‌ !Hello World ) خودمونه!. پس این کُد ساده رو ببیند که چقدر قَشنگ این پیغام رو در کُنسول چاپ می‌کنه:‌ print("Hello World!") به همین سادگی که مشاهده کردید، با استفاده از متد print پیغام Hello World رو چاپ کردیم. اگر این دستور رو اجرا کنید، با همین پیغام در کُنسول مواجه میشید. پس این تابع برای چاپ مقادیر در سوئیفت هستش. شاید دقت کرده باشید که سِمی‌کالُن نذاشتم! سوئیفت این اجازه‌ رو میده که بدون گذاشتن سِمی‌کالُن برناممون رو اجرا کنیم که البته بذارید هم مشکلی پیش نمی‌آید، مگر در موقعی که چندین دستور در یک خط داشته باشید که اون موقع واجب میشه! تابع print یک تابع سراسری در سوئیفت هستش که چندین آرگومانت دریافت می‌کنه و اساس کارش، چاپ اطلاعاتی هستش که بهش میدیم. و حالا یه سری آرگومانت‌های پیش‌فرض‌ هم میگیره که می‌تونیم بسته به نیاز اون‌ها را تغییر بدیم. در اولین آرگومانت، ما تا هر چند‌تا مقادیر یا همان آیتم‌ها که بخواهیم می‌توانیم وارد کنیم و در خروجی نمایش دهیم. به این شکل که می‌بینید: print("www.iostream.ir", "www.fanoox.com", item3, item4, ...) در آرگومانت دوم، که separator هستش، می‌توانیم مشخص کنیم که اگر دارای چندین آیتم اطلاعات بودیم، در بین هر کدام از این اطلاعات، چه نمادی/علامتی قرار گیرد؟. که ما می‌تونیم اون نماد/علامت رو در بین دو "" مشخص کنیم. به عنوان مثال:‌ print("www.iostream.ir", "www.fanoox.com", separator : " :)) ") // Output the ==> www.iostream.ir :)) www.fanoox.com هما‌نطور که مشاهده کردید، می‌توانیم از هر نماد/علامتی که دوست داشتیم در بین انبوهی از داده‌ها استفاده کنیم. در آرگومانت سوم، می‌توانیم مشخص کنیم که اطلاعات به خط بعدی ( new line ) یا در همان خط فعلی چاپ شوند یا خیر که به صورت زیر است: print("www.iostream.ir", terminator : "") print("www.fanoox.com") /*Output the => www.iostream.ir www.fanoox.com that not of include is new line */ در حالت پیش‌فرض تابع به صورت "terminator : "\n هستش که به معنی در " در پایان چاپ اطلاعات، اطلاعات دیگر را که بعد از این مقادیر چاپ‌شده می‌آیند را چاپ کن ". برای تعریف متغییر در سوئیفت به دو صورت می‌تونید عمل کنید: تعریف متغییر بدون تعیین نوع تعریف متغییر با تعیین نوع همچنین ما دو نوع متغییر داریم: متغییری که مقدارش می‌تونه در ادامه‌ی برنامه تغییر کنه متغییر که مقدارش فقط در هنگام تعریف مشخص و قابل تغییر در سراسر برنامه نیست ( ثابت‌ها ) برای تعریف متغییر بدون نوع به این صورت عمل می‌کنیم:‌ var website_name = "www.iostream.ir" print(website_name) // or print("The website name is \(website_name)") همانطور که مشاهده می‌کنید تعریف یک متغییر که همواره مقدارش تغییر کنید با کلمه‌ی کلید var تعریف می‌شود و بعد از آن نام و مقدار آن می‌آید. در این حالت کامپایلر به صورت ضمنی خودش از رو مقدار، نوع متغییر را متوجه می‌شود و اگر شما این دستور را بنویسید: var website_name = "www.iostream.ir" print(type(of : website_name )) // or print("Type is => \(type(of : website_name )") // Result => String به شما مقدار String یا همان رشته‌ای را می‌دهد. اما در حالت تعیین نوع برای متغییر به این صورت است: var website_name : String = "www.iostream.ir" print(webiste_name) // or print("The website_name is \(website_name)") که شما صراحتا نوع را مشخص کردید و کامپایلر در اینجا و در ادامه‌ی برنامه‌ی مقدار غیری از String را قبول نمی‌کند. همان‌طور که مشاهده می‌‌کنید،‌ برای تعریف نوع برای متغییر باید از دو کالُن ( : )‌ استفاده کنیم و سپس حرف اول نوع متغییر را بزرگ بنویسم ( البته در این زبان ) مانند؛‌ Int و سپس با گذاشتن علامت انتساب ( = ) مقدار مورد نظر خود را به آن بدهیم. نکته‌ای دیگری که وجود دارد در چاپ کردن مقادیر است که شما می‌توانید با دو روش فوق که ذکر شده‌ است، مقادیر را چاپ کنید که یکی بصورت آیتم به آیتم یعنی print( item1, item2, item3 , ...) و تا هر چند آیتم را که حاوی مقادیر هستند به خروجی بفرستید و نمایش دهید و اما در حالت دوم باید Syntax متفاوتی استفاده کنید و آن هم ادغام رشته با مقادیر متغییر‌هاست! که مثالش را بالا برای شما عزیزان زده‌ام و مقادیر متغییر‌ها باید بین دو پرانتز و قبل پرانتز از یک بک‌اسلش رو به عقب استفاده کنید!‌. و اما بریم سراغ ثابت‌‌ها! از اسم این متغییر‌ها پیداست که یک بار تعریف می‌شوند و مقدار ثابتی دریافت می‌کنند و در ادامه‌ی برنامه و یا رَوند پُروژه هیج تغییری نمی‌کنند و در طول برنامه یا پروژه مقادیرشون ثابته! بیاید با یک مثال شروع کنیم؛ ثابت‌ها در سوئیفت با کلمه‌ی کلید let تعریف می‌شوند و همانند متغییر‌ها شامل نام و نوع هم می‌شوند: let _website_name = "www.iostream.ir" _webiste_name = "iostream.ir" // Error , beacuse it's a constant print(_website_name) // or print("The website name => \(_website_name)") هما‌نطور که می‌بینید، تغییر دادن مقادیر ثابت‌ها باعث بروز خطا میشه و اجازه‌ی چنین کاری به شما داده نمیشه. و برای تعریف با تعیین نوع هم به این شکل عمل می‌کنیم: let _number : Int = 20 _number = 40 // Error , beacuse it's a constant print(_number) // or print("The number => \(_number)") تا همین‌جا کفایت می‌کنه و تا شما یک قهوه نوش‌جان کنید و این کد‌ها رو آزمایش کنید و همچنین از صِحَت نتیجه اطمینان حاصل کنید، منم یه کوچولو استراحت می‌کنم و جلسه‌ی دوم رو که شامل نحوه‌ی نام‌گذاری صحیح برای متغییر‌ها و ثابت‌ها و نام‌گذاری‌های مجاز و همچنین یکم بحث رو می‌کشونیم سمت دستورات شرطی و حلقه‌ها. امیدوارم این جلسه از دوره‌ی آموزش زبان برنامه‌نویسی سوئیفت مورد رضایت شما عزیزان واقع شده باشه. هر سوال و ابهامی داشتید، می‌تونید کامنت کنید تا براتون توضیح بدم. در پناه حق، هر کجای کشور عزیزمون ایران هستید، شاد، سرافراز و موفقیت روز‌افزون داشته باشید.
  18. 1 امتیاز
    درود، دو تا سیستم فونت تعریف کنید، یکیش لاتین برای انگلیسی و دیگری فونت مورد نظر برای فارسی. برای مثال، همچین چیزی رو در نظر داشته باشید: FontLoader { id: fontEnglish source: "english-font.ttf" } FontLoader { id: fontPersian source: "persian-font.ttf" } در نهایت در یک دستور شرطی با توجه به واکنش بر اساس مشخصه‌ی فکوس و یا هر چیزی که نیاز هست فونت‌ها رو اعمال کنید. برای مثال به صورت زیر: TextField { //Todo... property bool isLatin : false font.family: isLatin ? fontEnglish.name : fontPersian.name onPlaceholderTextChanged: { //ToDo... } }
  19. 1 امتیاز
  20. 1 امتیاز
    سلام و درود، مدتی است از سرویس‌های کاوه‌نگار جهت استفاده در پروژه‌‌های خودم استفاده می‌کنم و مطمئنم یکی از بهترین سرویس‌دهنده‌های ایرانی در زمینه‌ی پیام کوتاه است. متأسفانه همانطور که می‌دانید بسیاری از سرویس‌دهنده‌ها در ایران به خاطر عدم شناخت دقیق از اهمیت و کاربرد سی++ هیچ حرکتی در توسعه‌ی سرویس‌های خود در رابطه با سی++ را نمی‌کنند. بنابراین، جدیداً تصمیم گرفتم کیت‌های توسعه در قالب رابط‌های برنامه‌نویسی مورد نیاز رو برای این چنین شرکت و سرویس‌ها آن ارائه کنم. معرفی سرویس پیام کوتاه کاوه‌نگار کاوه نگار با ارائه وب‌سرویس پیامک و تماس صوتی پیشرفته برای توسعه دهندگان ،امکان ارسال و دریافت پیامک و برقراری تماس اینترنتی را در اغلب سرویس های نرم افزاری مهیا می کند. اهمیت وجود این سرویس در زبان‌هایی مانند C و ++C همانطور که می‌دانید با توجه به اهمیت این زبان‌ها و به خصوص پشتیبانی از کتابخانه‌های بسیار مدرن در توسعه‌ی اپلیکیشن‌ها و وب‌ها کاربرد بسیاری دارند که شاید در کشور ما آن‌چنان با آن‌ها آشنا نیستیم. بنابراین وجود سرویس‌های ارسال پیامک در قالب زبان‌ سی‌پلاس‌پلاس می‌تواند کمک بسیار بزرگی به توسعه‌دهندگان و علاقه‌مندان آن در حوزه‌های توسعه‌ی نرم‌افزار و انواع برنامه‌های موبایل و وب کمک کند. ساختار اولیه خروجی سرویس کاوه‌نگار به صورت زیر است: { "return": { "status":404, "message":"متد تعریف نشده است" }, "entries": { null } } در صورتی که مقادیر ارسالی صحیح و مطابق با اطلاعات کاربری موجود در کاوه‌نگار باشد نتیجه‌ی برگشتی آن به صورت زیر خواهد بود: { "return": { "status": 200, "message": "تایید شد" }, "entries": [ { "messageid": 8792343, "message": "خدمات پیام کوتاه کاوه نگار", "status": 1, "statustext": "در صف ارسال", "sender": "10004346", "receptor": "0914XXXXXXX", "date": 1356619709, "cost": 120 } ] } نمونه‌ی اولیه که توسعه داده شده، با مفهوم اولیه جهت ارسال پیام کوتاه بر اساس کلید و شماره‌های ارسالی آماده شده که کد نمونه‌ی آن به صورت زیر خواهد بود. #include <iostream> #include <Kavenegar> int main() { //! Your Api Key std::string apiKey {"Your Api-Key"}; //! Kavenegar Default Sender Number std::string senderLine {"10004346"}; Kavenegar::KavenegarApi api(MethodType ,"10004346",apiKey); //ToDo.. try catch exception handling. api.send("09140000000","Hi!"); std::cout << "Result : " << api.getResult(); //JSon Output return 0; } نکته: نمونه‌ی ساخته شده کامل و با تمام جزئیات موجود در کاوه‌نگار تکمیل و توسعه داده خواهد شد. لینک مربوط به کیت توسعه در گیت‌هاب. جهت استفاده از این نمونه توجه داشته باشید که جهت اجرای وب‌سرویس آن نیاز به نصب Curl و RapidJson خواهید داشت.
  21. 1 امتیاز
    سلام صرفا از این جهت این سوال را میپرسم که خب تا اینجای مطلبی که نوشتین برای بسیاری از افراد، همان طور خودتون گفتین دیوانگی بنظر میرسه پس چرا یکم این دیوانگی بیشتر نباشه؟. این امکان رو هم بررسی کردین که آیا میشه جاوااسکریپت سمت فرانت رو هم با سی++ بزنیم زمین؟ یعنی یک سیستم کاملا سی++ رو بشه برای برنامه نویسی تحت وب پیاده کرد؟ حتما ازاین که مثلا نودجی.اس هم بسیار سرعت خوبی داره و سروصدای خوبی هم به پا کرده که جاوااسکریپت در دوسمت برنامه نویسی وب وارد شده و سریعت بخشیده و.... هم زیاد شنیدین، ولی خب در بحث سرعت هنوز سی و سی++ رو نمیتونن رد کنن. مشتاق خوندن پستهای بعدی تون هستم.
  22. 1 امتیاز
  23. 1 امتیاز
    منظور محدود کردن نیست، در واقع شما عمل تأیید یا امضاء برای یک شیء را جهت استفاده در یک کتابخانه یا برنامه‌ی دیگر اعمال می‌کنید. این واژه‌ی کلیدی به شما اجازه می‌دهد اطلاعات کلاس ذخیره شده را در مراحل کامپایل به لینکر مشخص کنید، با توجه به مثال مربوطه استفاده از این دستور اساساً با توجه به صِفتِ dllexport به لینکر می‌گوید که شیء مورد نظر برای استفاده صادر می‌شود که توسط سایر کتابخانه‌ها (DLL) یا برنامه‌ها قابل استفاده خواهد بود. در این حالت تعاریف مربوط به اعلان‌های موجود باید در برنامه‌ی مشابه پیاده سازی شود، در غیر اینصورت خطای لینکر ساطع می‌شود. زمانی از این روش استفاده می‌شود که بخواهید DLL ای را ساخته و دیگر موارد را به آن لینک (پیوند) کنید. در صورتی که صفت dllimport مشخص شود عمل عکسِ آن صورت می‌گیرد؛ پیاده‌سازی‌های (implementation) مربوطه به آن برای استفاده در برنامه‌ی شما وارد می‌شوند. استفاده از dllimport نیز یک گزینه‌ی اختیاری است. در صورت استفاده از این کلیدواژه، کامپایلر کد کارآمد‌تری را تولید می‌کند. با این حال بهتر است شما برای دسترسی به نماد‌ها و اشیاء داده‌های عمومی از آن استفاده کنید. به مثال‌های زیر توجه کنید: __declspec(dllexport) void messageBox (std::string_view msg); __declspec(dllimport) void messageBox (std::string_view msg); معمولاً پیشنهاد می‌شود برای داشتن یک API خوب به صورت زیر پیاده سازی شود. #ifdef LIBRARY_API #define LIBRARY_API __declspec(dllexport) #else #define LIBRARY_API __declspec(dllimport) #endif نمونه مثال از فایل سرآیند: #ifndef MESSAGELIB_HPP #define MESSAGELIB_HPP #pragma once #include <iostream> #include <string_view> #include <string> #ifdef LIBRARY_API #define LIBRARY_API __declspec(dllexport) #else #define LIBRARY_API __declspec(dllimport) #endif class LIBRARY_API MessageBox { public: MessageBox(); ~MessageBox(); std::string_view message(std::string_view msg); }; #endif // MESSAGELIB_HPP تعاریف مربوطه: #include "messagelib.hpp" MessageBox::MessageBox() { } MessageBox::~MessageBox() { } std::string_view MessageBox::message(std::string_view msg) { return msg; } استفاده از کتابخانه در برنامه‌ها یا کتابخانه‌های دیگر: #include <iostream> #include "messagelib.hpp" using namespace std; int main() { MessageBox msg; cout << msg.message("Hello Boy!") << endl; std::cin.get(); return 0; }
  24. 1 امتیاز
    درود، واژه‌ی کلیدی__decspec با صفتِ dllexport به شما اجازه می‌دهد تا توابع و متغیر‌ها را برای اعلان در مرحله‌ی ورود و خروج کنترل کنید. زمانی که بخواهید داده‌ها، توابع، کلاس‌ها و یا توابع عضو کلاس را از طرف DLL مورد استفاده قرار دهید از این کلمه‌ی کلیدی استفاده می‌شود.
  25. 1 امتیاز
    فعلاً به بلوغ نرسیده، باید در سمت مرورگر‌ها و سرور بهینه‌سازی بشه.
  26. 1 امتیاز
    سلام، این روش‌ها که بهشون اشاره کردین به عنوان متد (method) انتقال اطلاعات بین سرور و کلاینت هستند. برای دریافت و یا اعمالِ یک درخواست برای انجام کار مانند انتقال، به‌روز‌رسانی، دریافت، حذف و غیره از متد‌هایی مثل GET, POST, DELETE, PUT, PATCH استفاده می‌شود که متد‌های Get و Post دو نمونه‌ی مهم و پرکاربردی از این روش‌ها محسوب می‌شوند. در اندروید شما برای اینکه بخواهید اطلاعاتی را از سرور خود دریافت و یا انتقال دهید، اگر اون پروتکل تحت http یا https باشه می‌توانید تحت این متد‌ها تراکنش را انجام دهید. بنابراین هیچ فرقی بین متد‌های GET و POST در اندروید و HTML وجود نداره چون این‌ها یک سری متد‌های استانداردِ از قبل تعریف شده برای پروتکل‌ HTTP بشمار می‌آیند.
  27. 1 امتیاز
    با تشکر از شما، متوجه شدم که چگونه باید اشیاء را در 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} } } } } } خروجی نمونهٔ بالا :
  28. 1 امتیاز
    با سلام و درود، روشی که به کار گرفته‌اید صحیح است اما حرفه‌ای و پویا نیست. پیشنهاد من ایجاد یک کلاس در سمت بک‌اِند تحت C++ مشتق شده از QObject است. برای مثال کلاس زیر را در نظر بگیرید. #pragma once #ifndef STYLE_HPP #define STYLE_HPP #include <QObject> #include <QColor> class Style : public QObject { Q_OBJECT Q_PROPERTY(QColor primary READ primary WRITE setPrimary NOTIFY primaryChanged) Q_PROPERTY(QColor secondary READ secondary WRITE setSecondary NOTIFY secondaryChanged) Q_PROPERTY(int h1 READ h1 WRITE setH1 NOTIFY h1Changed) public: Style(); ~Style(); QColor primary () const; QColor secondary () const; int h1 () const; public slots: void setPrimary (const QColor &color); void setSecondary (const QColor &color); void setH1 (const int &size); signals: void primaryChanged (); void secondaryChanged(); void h1Changed(); private: QColor m_primary; QColor m_secondary; int m_h1; }; #endif // STYLE_H #include "style.hpp" Style::Style() { this->m_primary = "gray"; this->m_secondary = "black"; this->m_h1 = 12; } Style::~Style() { } void Style::setPrimary(const QColor &color) { if (color != m_primary) { m_primary = color; emit primaryChanged(); } } QColor Style::primary() const { return m_primary; } void Style::setSecondary(const QColor &color) { if (color != m_secondary) { m_secondary = color; emit secondaryChanged(); } } QColor Style::secondary() const { return m_secondary; } void Style::setH1(const int &size) { if (size != m_h1) { m_h1 = size; emit h1Changed(); } } int Style::h1() const { return m_h1; } تابع Main #include <QGuiApplication> #include <QQmlApplicationEngine> #include <QQmlEngine> #include <QQmlContext> #include "style.hpp" int main(int argc, char *argv[]) { QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QGuiApplication app(argc, argv); QQmlApplicationEngine engine; QQmlContext *context = engine.rootContext(); Style style; const QUrl url(QStringLiteral("qrc:/main.qml")); context->setContextProperty("Style", &style); QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, &app, [url](QObject *obj, const QUrl &objUrl) { if (!obj && url == objUrl) QCoreApplication::exit(-1); }, Qt::QueuedConnection); engine.load(url); return app.exec(); } و در بخش QML به این صورت: import QtQuick 2.12 import QtQuick.Window 2.12 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 Window { visible: true width: 640 height: 480 title: qsTr("Hello World") Rectangle { anchors.fill: parent color: Style.primary ColumnLayout { anchors.centerIn: parent Text { text: qsTr("Hello, World!") color: Style.secondary font.pixelSize: Style.h1 } Slider { from: 12 to: 64 snapMode: Slider.SnapAlways stepSize: 0.5 onValueChanged: { Style.setH1(value) } } Switch { onCheckedChanged: { if(checked) { Style.setPrimary("green") Style.setSecondary("orange") } else { Style.setPrimary("gray") Style.setSecondary("black") } } } } } } مثالی که زدم صرفاً یک روش مفهومی (Concept) است و شما می‌تونید تغییر و توسعش بدین.
  29. 1 امتیاز
    تو برنامه ای که در به ارث رسیده مقدار پارامتر اول در SELECT صفر داده شده و همین استفاده ازآن شده است ضمن آنکه برنامه برای محیط Windows بوده و در محیط VS کمپایل شده.
  30. 1 امتیاز
    سلام، شما باید به نسخه‌ی خود Qt هم توجه کنید، شما از نسخه‌ی کیوت ۵.۱۲ داری استفاده می‌کنی که NDK 20 رو پشتیبانی نمی‌کنه، مگر اینکه فلگ -nostdlib++ رو اعمال کنی که در زیر مثال زدم. بنابراین تنها از کیوت ۵.۱۳ به اینور پشتیبانی می‌شه، برای نسخه‌های پایین‌تر از NDK R18 استفاده کن. QMAKE_LINK += -nostdlib++ درضمن NDK ویندو برای ویندوز هست نباید اون رو برای لینوکس استفاده کنی (نسخه‌ی مخصوص لینوکس رو دریافت کن). بعد از دریاف جهت به‌روزرسانی‌ مخازن هم حتماً باید از شبکه‌ی پایدار استفاده کنی تحت وی‌-‌پی‌-ان تا بتونی دانلود رو به درستی انجام بدی. قبل از پرسش‌های تکراری هم حتماً یک جستجو در وب‌سایت انجام بده تا به پاسخ‌های مرتبط برسی : آخرین تغییرات و به‌روزرسانی‌های NDK - برنامه نویسی تحت محصولات گوگل - جامعه‌ی برنامه‌نویسان مُدرن ایران مشکل خروجی گرفتن از اندروید در Qt 5.12 - موبایل و اِمبِد‌ها - جامعه‌ی برنامه‌نویسان مُدرن ایران پیغام خطا هنگام خروجی گرفتن در اندروید - فناوری Qt Quick و QML - جامعه‌ی برنامه‌نویسان مُدرن ایران
  31. 1 امتیاز
    باسلام تقریبا مدت زیادی است که درگیر Socket programming و Thread هستم. و هر چند وقت یکبار سوالاتی را در مورد چگونگی استفاده از آنها در فروم های مختلف مطرح و تا حدودی پاسخ خود را یافته ام. با توجه به اینکه گذشت زمان سوالات و شرایط تغییر کرده و لذا خواستم سوالاتی از این دست را یکبار دیگر از ابتدا مطرح و جواب کاملی برای هر کدام داشته باشم. اگر چه امکان دارد جواب هرکدام از این سوالات بطور پراکنده و جداگانه در سایتهای مختلف موجود باشد. علاوه بر آن کمتر جایی یدم که این دو موضوع را با هم بررسی کرده باشند یا فقط به مبحث Thread پرداخته اند ویا فقط درباره Socket توضیح داده اند آن هم فقط در مورد بعضی از توابع مرتبط. حتما دوستان با ترتیب اجرای دستورات و نحوه ایجاد و مفهوم سوکتهای سمت سرور و کلاینت آشنا هستند و هفت نحوه استفاده از آنها نیست بلکه هدف این است اگر من بخواهم از این توابع در Thread های مختلف استفاده کنم آیا امکان پذیر است. آیا پاسخ های داده شده برای محیط Windows, Linux, ... هردو درست است علاوه بر کتابخانه های همراه کمپایلرها کتابخانه های دیگری نظیر Boost - Poco - ACE - Qt - ... هم کتابخانه ای برای کار با شبکه دارند وضعیت توابع مشابه در آنها چگونه است. سوالات رو از سمت سرور شروع میکنم. فرض لازم است سمت سرور 3 سوکت سروری داشته باشیم. SOCKET AcceptSock1; SOCKET AcceptSock2; SOCKET AcceptSock3; حال باید دستورات زیر اجرا شود int InitFunction(SOCKET &AcceptSock) { SOCKET AcceptSock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); if (AcceptSock == INVALID_SOCKET) { printf("Function socket failed with error : %u\n", WSAGetLastError()); return 0; } int iTimeout = 500; BOOL option = TRUE; int iResult = setsockopt(AcceptSock, SOL_SOCKET, SO_RCVTIMEO, (char *)&iTimeout, sizeof(iTimeout)); if (iResult == SOCKET_ERROR) { printf("Function setsockopt failed with error: %u\n", WSAGetLastError()); return 0; } SOCKADDR_IN client_sin; SOCKADDR_IN local_sin; int iAddrSize = sizeof(client_sin); int iPort = 12345; // select the local interface, and bind to it local_sin.sin_addr.s_addr = htonl(INADDR_ANY); local_sin.sin_family = AF_INET; local_sin.sin_port = htons(iPort); if (bind(AcceptSock, (struct sockaddr *)&local_sin, sizeof(local_sin)) == SOCKET_ERROR) { printf("Function bind failed with error: %u\n", WSAGetLastError()); return 0; } if (listen(AcceptSock, 32) == SOCKET_ERROR) { printf("Function listen failed with error: %u\n", WSAGetLastError()); return 0; } } فانکشن بالا باید برای AcceptSock1 و AcceptSock2 و AcceptSock3 اجرا شود. با اجرای سه کد زیر. InitFunction(AcceptSock1); InitFunction(AcceptSock2); InitFunction(AcceptSock3); سوال آیا من میتوانم هرکدام از سه دستور بالا را در Thread های مختلف اجرا کنم ویا باید حتما در Thread main اجرا شود. برای پذیرش کلاینتهایی که درخواست اتصال دارند از تابع زیر استفاده میکنیم int ProcessFunction(SOCKET &AcceptSock) { fd_set fd; timeval tv; SOCKADDR_IN client_sin; int iAddrSize = sizeof(client_sin); while (true) { tv.tv_sec = 3; tv.tv_usec = 0; FD_ZERO(&fd); FD_SET(AcceptSock, &fd); int iResult = select(0, &fd, NULL, NULL, &tv); if (iResult == SOCKET_ERROR) { printf("Function select failed with error: %u\n", WSAGetLastError()); closesocket(AcceptSock); return 0; } if (iResult == 0) { continue; } SOCKET soc = accept(AcceptSock, (struct sockaddr *) &client_sin, &iAddrSize); if (soc == INVALID_SOCKET) { printf("Function accept failed with error: %u\n", WSAGetLastError()); continue; } //... Do } } که باید برای AcceptSock1 و AcceptSock2 و AcceptSock3 اجرا شود. با اجرای سه کد زیر. ProcessFunction(AcceptSock1); ProcessFunction(AcceptSock2); ProcessFunction(AcceptSock3); سوال سوال آیا من میتوانم هرکدام از سه دستور بالا را در Thread های مختلف اجرا کنم کلا لازم نیست هیچ گونه عملیات لاکی صورت گیرد. آیا من میتواند از AcceptSock1 در دو Thread مختلف استفاده کنم (پاسخ خیر است فقط میخواستم جواب در اینجا باشد). اگر استفاده کنم چه اتفاقی پیش میآید. فانکشن ()WSAGetLastError قطعا Threadsafe نیست ولی آیا توابع دیگری که کد خطا را بروز میکنند Threadsafe نیستند. برای خواندن و نوشتن اطلاعات از Socket پذیرش شده از توابع زیر استفاده می کنیم int SendMessageFunction (SOCKET sock, const char * msg, int len) { fd_set fd; timeval tv; tv.tv_sec = 0; tv.tv_usec = 0; FD_ZERO(&fd); FD_SET(sock, &fd); int iResult = select(0, NULL, &fd, NULL, &tv); if (iResult == SOCKET_ERROR) { printf("Function SendMessage failed with error: %u\n", WSAGetLastError()); return -1; } int rc = send(sock, (char *)msg, len, 0); if (rc != len) { return -1; } return 1; } int ReceiveMessageFunction(SOCKET sock, char * msg, int &len) { fd_set fd; timeval tv; tv.tv_sec = 0; tv.tv_usec = 0; FD_ZERO(&fd); FD_SET(sock, &fd); int i = select(0, &fd, NULL, NULL, &tv); if (i == SOCKET_ERROR) { printf("Function ReceiveMessage failed with error: %u\n", WSAGetLastError()); return -1; } else if (i == 0) { // no data on socket return 0; } // //... //len = ... //... int rc = recv(sock, (char *)msg, len, 0); // ... return 1; } آیا من میتوانم تاوابع بالا را در Threadهای مختلف استفاده کنم و یا خیر. آیا امکان خواندن از یک سوکت توسط دو Thread مختلف امکان پذیر است. نوشتن چطور آیا میتوان یک Thread از Socket بخواند و Thread دیگری در آن بنویسد. با توجه به این موضوع که در یکی از صفحات اینترنتی بیان شده بود که Boost برخلاف کتابخانه های دیگر Threadsafe است (اگرچه امروز هرچه گشتم دوباره آنرا پیدا نکردم) پاسخ با توجه به پلتفورم )Windows, Linux, ..) و کتابخانه مورد استفاده (پیشفرض کمپایلر - ACE - Poco - Boost Qt - ...) در نظر گرفته شود. متشکرم
  32. 1 امتیاز
    یه سوال داشتم که خیلی وقت هست درگیرش هستم. من خودم به صورت عادی از win32 در ++C استفاده میکنم و برای ساختن حتی یه button کلی زور میزنم و کد مینویسم برای رویداد ها و لوکیشن و ... حالا بماند که برای تنظیم یک رنگ برای یک button یا text چقدرر دردسر دارم. من قبلا با زبان #C کار میکردم و با رابط گرافیکی و طراحی رابط گرافیکی اون به خوبی آشنا هستم . البته میدونم که امنیت برنامه های .net کلا ضعیف هست اما از لحاظ گرافیکی به راحتی میشه هر نوعی که بخوایم در کمترین زمان طراحی کنیم. البته اگر بخوایم باز کد ها و دستورات رو با .net بنویسیم چیز جالبی نمیشه. البته نا گفته نماند که به Qt ام برای طراحی فکر کردم اما چند تا مشکل دارد . اولی اینکه حجم برنامه رو به شدت میبره بالا . دوم تعداد فایل های برنامه رو میبره بالا . سوم من در کل IDE برنامه نویسیم در Visual studio هست و به اون بیشتر عادت دارم چون خیلی ساده تر هست نسبت به Qt و اگر بخوام پلاگین های qt رو بریزم توی vs باز هم باید به صورت کد و لوکیشن و ... انجام بدم که تقریبا مثل win32 میشه فکر کنم. من خودم شخصا برای این مشکل به این فکر افتادم که رابط گرافیکی رو با c# بنویسم و همه کد ها رو توی یه قالب dll که به زبان c++ نوشته شده از #C فراخانی کنم. نظر شما چیه؟ راه حل بهتری سراغ دارید؟
  33. 1 امتیاز
    ممنونم. تونستم دلیل اینکه چندین بار داده ای را که از پورت میخواند امیت میکرد را پیدا کنم دلیلش اینه که چون connect مربوط به سیگنال و اسلات را در متد سازنده کلاسم گذاشته بودم. نمیدونم چرا اما زمان که صفحه cpp ایجاد میشد این دستور connect چندین بار اجرا میشد . برای همین ۸ بار امیت مربوط به سیگنال را می خوند. خلاصه اینکه تابعی نوشتم که کار connect را انجام بده در زمانی که میخوام و از توی تابع سازنده کلاس بیرون اوردمش و اینکه پارامتر پنجم مربوط به connect را هم نوشتم Qt::UniqeConnect فکر کنم بود.
  34. 1 امتیاز
    خواهش میکنم. خدا رو شکر که حل شد ولی دنبال دلیل باشید و نگذارید بیش از این مشکل توی برنامه باقی بمونه یعنی دلیل چند بار امیت شدن رو متوجه بشید وگرنه جلوتر ممکنه مشکلات مشابهی پیش بیاد و ترکیب این مشکلات با هم غیر قابل حل باشه. توی یک پروژه تیم قبلی کلی تایمر توی لایه ویو استفاده کرده بود و کل کدها توی یه تایمر کلی بود و خلاصه خیلی بهم ریخته بود سر همین یه سیگنال روشن شدن دستگاه دوبار ارسال میشد برای این که همین مشکل ساده رو حل کنم نزدیک یک هفته ازم وقت گرفت تا انجامش بدم تازه مدام هم گوش به زنگ خطر بودم چون میدونستم اگر مشکل دیگه ای پیش بیاد هیچ تضمینی نیست بشه درستش کرد چون هر تایمر جدا داشت کار میکرد و روی یک قسمت از کد اثر میگذاشت و با توجه به این که کد کثیف بود نمیشد درست سر در آورد و چون زمان پروژه از ددلاین عبور کرده بود وقتی برای ریفکتور کردن کد نبود در صورتی که اگر از همون اول به این مشکلات ریز رسیدگی میکردند این مشکلات پیش نمیاومد. پیشنهاد من هم برای شما اینه که دقیق سر در بیارید چرا داره چند بار امیت میشه بعد اگر منطقی بود و راهی برای حلش نبود از همین روشی که فعلا استفاده کردید استفاده کنید. سوالی هم بود بپرسید در خدمتیم.
  35. 1 امتیاز
    سلام، مدتی بود که نسخه‌ی ۲۰۱۷ کامپایلر MSVC با مشکل عدم بازگشت مقدار صحیح از نسخه‌ی استاندارد زبان مواجه بود. هرچند توسط توسعه دهندگان این مشکل به مایکروسافت گزارش داده شده بود اما ظاهراً مشکل همچنان پا برجاست. و اما مشکل، کد زیر را با کامپایلر MSVC2017 اجرا کنید: #include <iostream> int main() { std::cout << __cplusplus << std::endl; std::cin.get(); return 0; } اگر دقت کنید مقدار بازگشتی این کد 199711خواهد بود. در حالی که باید مقدار بازگشتی آن با توجه به استاندارد زبان باید یکی از دو مقدار 201402L یا 201403 باشد. برای حل این مورد من پچی را فراهم کردم که می‌تونید این مشکل رو حل کنید. علاوه بر این یک سری ماکرو نویسی جزئی انجام شده که با دقت بیشتر و مقدار بازگشتی از نام خود کامپایلر را برای شما ارائه دهد. طبق اصلاحیه کد دستوری آن به صورت زیر خواهد که تکه‌ای از کد‌های یکی از پروژه‌های من به نام Genesis بود که حالا اینجا به اشتراک گذاشتمش: #include <iostream> using namespace std; #include "macro.h" int main() { Macro mc; cout << "Hello World!" << endl; cout << "C++ Standard Version (MSVC) : " << __cplusplus << endl; cout << "C++ Standard Version (with bug fix in MSVC : " << __GENESIS_CPP_VALUE__ << endl; cout << "C++ Standard Version (with bug fix in MSVC using function: " << mc.get__cplusplus(false) << endl; cout << "Compiler name using flag true: " << mc.get__cplusplus(true) << endl; return 0; } خروجی: Hello World! C++ Standard Version (MSVC) : 199711 C++ Standard Version (with bug fix in MSVC : 201703 C++ Standard Version (with bug fix in MSVC using function: 201703 Compiler name using flag true: MSVC++ برای دریافت این اصلاحیه به مخزن آن مراجعه نمایید.
  36. 1 امتیاز
    با سلام تابع خاصی برای این کار ندیدم ولی تیکه کد زیر کار میکنه براتون نوشتمش : QByteArray data = {"test values are good"}; qDebug() << data; int bufSize = 3; int dataSize = data.size(); dataSize = dataSize % bufSize ? dataSize / 3 + 1 : dataSize / 3; for (int i = 0; i < dataSize; ++i) { qDebug() << data.mid(i * bufSize, bufSize); }
  37. 1 امتیاز
    این تکنیک پایین هم میشه استفاده کرد QTimer::singleShot(1000, [this]() { //code 1 } ); QTimer::singleShot(2000, [this]() { //code2 } );
  38. 1 امتیاز
    اتفاقاً من یه چیزی شبیه به همین مورد رو توی برنامه‌های خودم ساختم و از همین کنترلی که گفتم یعنی GridLayout استفاده کردم که نگه‌دارنده‌ی داخلی رو واکنشگرا بر اساس تغییر اندازه تنظیم می‌کنه مثل همین تلگرام. منطق پیاده سازی این یکم باید بر اساس ابعاد صفحات نمایشی و طول و عرض پنجره پیاده سازی بشه که نسبت به نوع پلتفرم متفاوته.
  39. 1 امتیاز
    راه حل این مسئله ساده‌تر از پیچیدگی که فکر می‌کنید هست. کافیه از GridLayout استفاده کنید که نسبت به مشخصه‌ی flow می‌تونید به همین چیزی که می‌خواهید برسید. مثال: https://doc.qt.io/qt-5/scalability.html ApplicationWindow { id: root visible: true width: 480 height: 620 GridLayout { anchors.fill: parent anchors.margins: 20 rowSpacing: 20 columnSpacing: 20 flow: width > height ? GridLayout.LeftToRight : GridLayout.TopToBottom Rectangle { Layout.fillWidth: true Layout.fillHeight: true color: "#5d5b59" Label { anchors.centerIn: parent text: "Top or left" color: "white" } } Rectangle { Layout.fillWidth: true Layout.fillHeight: true color: "#1e1b18" Label { anchors.centerIn: parent text: "Bottom or right" color: "white" } } } }
  40. 1 امتیاز
    فعال‌سازی مشاوره‌های ویژه در صفحه‌ی اینستاگرام و تلگرام.
  41. 1 امتیاز
    سلام، کتابخانه‌های Win32 و MFC هرچند کتابخانه‌های قدرتمندی هستند اما باید در نظر داشته باشید این‌ها مُختصِ پلفترم ویندوز بوده و بر اساس API های ویندوز ارائه شدن و مسلماً کاربرد‌های آن‌چنان به‌روز و چند منظوره‌ای مثل Qt رو ندارند. کتابخانه‌ی پیشنهادی خود مایکروسافت در قالب چهارچوب دات‌نت است که برای سی++ هم UWP قابل استفاده بوده و شما می‌تونید رابط کاربری مدرن رو هم با WPF توسعه دهید (اما انتظار نداشته باشید در حد Qt خارق‌العاده باشه). با توجه به اینکه شخصاً تعامل خوبی با دات‌نت و سی‌شارپ دارم و در مواقعی که صلاح می‌دونم ازش استفاده می‌کنم، نیاز هست تا شمارو در جریان یک واقعیت قرار بدم (که سوال بسیاری از دوستان بوده)! شما برای اینکه برنامه‌ای رو تحت هر زبانی اجرا کنید مسلماً نیاز به یک سری کتابخانه‌ها و پیش نیازاتی خواهید داشت! برای مثال در سی‌شارپ شما نیاز به دات‌نت دارید و در سی++ نیاز به STL، Qt، ‌Boost و غیره! حالا کتابخانه‌ی پیشفرض سی++ STL و پیشفرض سی‌شارپ Net. هست! حالا با توجه به اینکه شما یک برنامه‌ی ساده ز نوع "سلام دنیا!" بنویسید! چیزی که در سی++ ارائه خواهد شد حدود چند کیلوبایت است که برای اجرای اون تنها نیاز به فایل‌های msvcr و msvcp و یا vcruntime خواهید بود که جمعاً حدود ۱ تا ۲ مگابایت نیستند! اما برعکس در سی‌شارپ شما بخوای همین برنامه‌ی ساده رو بنویسی خبری از این سادگی نیست! نیازمند پکیج حجیمی از دات‌نت خواهی بود که باید نصبش کنی در ویندوز وقتی شما با سی‌شارپ برنامه‌نویسی می‌کنید به دلیل اینکه چهارچوب .Net و SDK‌های مربوط به دات‌نت بر روی سیستم‌عامل مستقر شده‌اند نیازی نیست تا کتابخانه‌های مربوط به دات‌نت رو در کنار برنامه‌ی خودتون قرار بدین (چون این‌ها در خود سیستم‌عامل نصب می‌شوند نه در کنار برنامه). دقت کنید آیا بدون نصب پکیج (Microsoft .NET Framework Redistributable) می‌تونید برنامه‌های مربوطه رو اجرا کنید؟ پاسخش مسلماً خیر خواهد بود! این پکیج حداقل بعد از نصب چیزی حدود ۲۰۰ تا ۷۰۰ مگابایت و حتی بیشتر کتابخانه‌ی دات‌نت استخراج خواهد کرد و این یعنی در کنار فایل اجرایی یک برنامه‌ی ساده از نوع "سلام‌ دنیا!" چنین حجم بزرگی از کتابخانه نیاز خواهد بود! اما شما متوجه این نمی‌شید چون به صورت پیشفرض موقع نصب برخی از ابزار‌های اختصاصی مایکروسافت مثل ویژوال استودیو، آفیس و غیره این پکیج نصب می‌شود! البته خارج از لطف هم نیست در برخی از نسخه‌های نهایی ویندوز مثل ویندوز ۱۰ بخش هسته‌ی کتابخانه همراه با هسته‌ی سیستم‌عامل ارائه میشه و آنچنان مثل قبل نیاز نصب بخش عظیم کتابخانه نیست. اما با این حال شما حتماً به پکیج مربوطه جهت اجرای تمامی قابلیت‌های برنامه‌ی خودتون نیاز خواهید داشت که اصلاً قابل مقایسه با یک برنامه‌ی ۱ تا ۲ مگابایتی تحت سی++ نیست. حالا با توجه به این آیا حجمی معادل ۸ تا ۲۰ مگابایت واقعاً مشکل محسوب می‌شود؟! شما فرض کن کتابخانه‌ی کیوت رو در قالب یک SDK روی هسته‌ی سیستم‌عامل خودت نصب کرده باشی! در این صورت همون فایل اجرایی چند کیلوبایتی نهایت حجم تولید شده از یک برنامه‌ی ساده است. تعداد فایل‌ها مربوط به همون کتابخانه‌ هستش! آیا می‌دونید تعداد فایل‌های دات‌نت بسیار بیشتر و در یک کلام چند برابر کتابخانه‌ی کیوت است!؟ برای اینکه متوجه واقعیتی (پنهان) شوید به این مسیر بروید: C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework وحشتناکه نه؟! مایکروسافت به همین راحتی سر برنامه‌نویس‌ها شیره می‌ماله و اون‌ها رو توجیح کرده که اگر کمی زیرک و حرفه‌ای به این مسائل باشید خواهید فهمید که در پشت این مزیت خوب چه جهنمی ساخته شده! در شناخه‌تر بودن محیط VS شکی نیست، اما این محیط توسعه یک محیط انحصاری برای پلتفرم ویندوز است. محیط توسعه‌ی Qt در هماهنگی بالا با خود کتابخانه مخصوصاً پشتیبانی از سیستم‌عامل‌های دیگه بسیار بهتر عمل می‌کنه. در مورد شباهتش به Win32 هم به خاطر درگیری مستقیم شما با کتابخانه هست. در رابطه با اینکه رابط کاربری رو با سی‌شارپ بنویسید و بک‌اند رو با سی++ کاملاً مخالفم! چون دارین خودتون رو قول می‌زنید! اگه قرار هست این کارو بکنید خب با همون VS تحت دات‌نت و C++/CLR کد‌نویسی کنید که تحت دات‌نت خواهد بود. راه حل بهتر اینه که واقعیت رو بپذیرید و قبول کنید که هر کار خارق‌العاده‌ای نیاز به تعامل بیشتری خواهد داشت. اگر می‌خواهید در قالب سرعت، قدرت، دسترسی‌، تعامل و خارج از هرگونه محدودیت برنامه‌نویسی کنید سی++ رو باید با تمامی سختی‌هاش بپذیرید! در غیر این صورت هیچ روشی برای قانع کردن خودتون وجود نداره. درضمن پاسخ اصلی به عنوان سوال : به صورت پیشنهادی کتابخانه‌ی Qt هست. کتابخانه‌های دیگری هم هستند مثل Juce یا wxWidgets.
  42. 1 امتیاز
    بسیار ممنون از پاسخ مفید و ععال شما !
  43. 1 امتیاز
    طبق گزارش @قاسم رمضانی منش عزیز، مبنی بر اینکه بلوک کُد بر روی مرجع فاقد شماره گذاری می‌باشد در یک به‌روز رسانی از نسخه‌ی ۹.۱۰ به ۹.۱۳.۱ در پلاگین HilightJS این مورد حل گردید. نمونه خروجی‌: // 'Hello World!' program #include <iostream> int main() { std::cout << "Hello World!" << std::endl; return 0; }
  44. 1 امتیاز
    کتابخانه‌ی Libcurl به خوبی از ویژگیِ Multi Session به عنوان ارسال و دریافت درخواست‌های هم‌‌زمان پشتیبانی می‌کنه این ویژگی به شما اجازه میده تا درخواست‌های هم‌زمان با تعداد بسیار بالا رو مدیریت کنید (بدون اینکه نگران از دست رفتن حتی یکی از سشِن‌ها بشید).
  45. 1 امتیاز
    با توجه به تحریم‌ها و سیاست‌های ضد ایرانی گوگل به نظرم بهتره حالا که داریم زمان میذاریم توسعه نقشه رو بر پایه API پارسیجو پیش ببریم یا حداقل طوری باشه که با پارسیجو هم سازگار باشه . پارسیجو یک شرکت ایرانی هست که با موتور جستجو کارش رو شروع کرد ولی خیلی فعال و با کیفیت پیش رفت . الان هم یک API تمیز برای نقشه ارائه داده که با نگاهی که من انداختم ارزش وقت گذاشتن داره. مورد دیگه ای که به نظرم نیاز هست نمودار در کیوت هست من این مدت داشتم روی نمودار توی کیو ام ال و ویجت وقت میگذاشتم متوجه شدم در حال حاضر نمودارها در کیوت بر پایه Graphics View Framework که طبق مطالعاتی که روش داشتم اصلا به درد نمیخوره علیرقم این که بسیار پر استفاده هست در صورتی که میخواید بیشتر بدونید میتونید جستجو کنید و ویدئو QtWS16- The Curse of Choice: An Overview of GUI technologies in Qt, Andy Nichols, The Qt Company هم لپ مطلب رو توضیح میده. تازه وضعیت توی کیو ام ال حتی بدتر از وضعیت توی QGraphicsView خود سی پلاس پلاس هست چون توی سی پلاس پلاس به QGraphicsScene دسترسی داریم برای اضافه کردن موارد گرافیکی دیگه ولی توی کیو ام ال به اون هم دسترسی نداریم و مثلا برای کشیدن یک مستطیل برای انتخاب کردن یک قسمت از چارت باید کلی دردسر بکشیم. در کل به نظرم نیاز هست با QQuickItem و بر پایه Scene Graph زده بشه که البته این مورد رو مدتی هست شروع کردم ولی به دلیل مشغله زیاد وقت نکردم تمومش کنم و فعلا برای کشیدن نمودارهای خطی استفاده داره که البته هنوز Axis رو هم نشون ندادم روش و دنبال روشی بودم که بشه از تو سی پلاس پلاس و بدون نیاز به کیو ام ال تکست رو هم رندر کنم ولی انگار چاره ای نیست فعلا و باید به صورت داینامیک متن از سی پلاس پلاس توی یکو ام ال درست کنم و موقعیتشون رو تنظیم کنم که البته روش کثیفی به نظر میرسه. در کل این لینک پروژه چارت بر پایه QQuickItem هست که تصمیم دارم تکمیلش کنم و علاوه بر اون میخوام نقشه بر پایه QQuickItem رو هم شروع کنم که البته اون رو بخش تحقیقش رو انجام دادم و در صورتی که زمان داشته باشم میشینم پاش و هیچ چالشی برای انجامش ندارم البته ممکنه سر همین رندر کردن متن توی پاپ آپ به همین مشکل بخورم توش که اون مشکل خاصی نیست میشه به همین روش داینامیک انجامش داد . پس پیشنهادات من این دو مورد هست : افزودن نقشه پارسیجو توسعه نمودارها بر پایه QQuickItem و Scene Graph و این هم لینک پروژه نمودار که البته تازه شروعش کردم ولی خوشحال میشم دوستان همکار کنند و نگاهی بهش بندازند .
  46. 1 امتیاز
    سلام .امیدوارم اشتراک گذاری ها و اطلاع رسانی هاتون حالا حالا ها ادامه داشته باشه... خدا قوت
  47. 1 امتیاز
    در این قسمت قصد داریم تا با چند مفهوم پایه‌ای تر در سیستم عامل ویندوز آشنا شویم. در ابتدا مفهوم (VAS (Virtual address spaces را مورد بررسی قرار می‌دهیم. فضای آدرس‌های مجازی (VAS) یک مُدل برای مدیریت بهتر حافظه می‌باشد، زمانی که یک پردازنده اقدام به خواندن یا نوشنتن در یک مکان حافظه می‌کند، از یک آدرس مجازی استفاده می‌کند. به عنوان بخشی از عملیات خواندن یا نوشتن، پردازنده آدرس مجازی را به آدرس فیزیکی ترجمه می‌کند. دسترسی به حافظه از طریق یک آدرس مجازی مزایای زیر را دارد : یک برنامه می‌تواند از محدوده‌ی مجاور آدرس های مجازی برای دسترسی به یک بافر حافظه بزرگ استفاده کند که در حافظه فیزیکی به یکدیگر متصل نیستند. یک برنامه می‌تواند طیفی از آدرس های مجازی برای دسترسی به بافری بزرگتر از حافظه فیزیکی موجود را مورد استفاده قرار دهد. حافظه‌ی فیزیکی ( که به اندازه 4 کیلوبایت می‌باشد) را به فایل دیسک می‌فرستد. صفحات داده یا کد بین حافظه‌ی فیزیکی و دیسک در صورت مورد نیاز منتقل می‌گردد (اولویت با صفحات قدیمی تر می‌باشد.که دیرتر به آنها مراجعه شده است). آدرس های مجازی مورد استفاده در فرایندهای مختلف از یکدیگر جدا شده اند. کد در یک فرآیند نمی‌تواند حافظه‌ی فیزیکی را که توسط فرآیند دیگری یا سیستم عامل مورد استفاده قرار می‌گیرد تغییر دهد. محدوده‌ی آدرس‌های مجازی که در فرآیند در دسترس است، فضای آدرس مجازی برای فرایند می‌باشد. هر فرایند حالت کاربر، دارای فضای آدرس مجازی خصوصی خود است. برای یک فرایند 32 بیتی، فضای آدرس مجازی معمولاً محدوده‌ی 2 گیگابایتی از 0x00000000 تا 0x7FFFFFFF است. برای یک فرآیند 64 بیتی فضای آدرس مجازی محدوده 8 ترابایتی 0x00000000000 تا 0x7FFFFFFFFFF است. طیفی از آدرس‌های مجازی گاهی اوقات طیفی از حافظه‌های مجازی نامیده می‌شوند. این نمودار برخی از ویژگی های آدرس مجازی را نشان می‌دهد: این نمودار فضاهای آدرس مجازی را برای دو فرایند 64 بیتی نشان می‌دهد: Notepad.exe و MyApp.exe هر فرایند دارای فضای آدرس مجازی خود است که از 0x000'0000000 تا 0x7FF'FFFFFFFF قرار دارد. هر بلوک آبی نشان دهنده یک صفحه (به اندازه 4 کیلوبایت) از حافظه مجازی یا فیزیکی است. توجه داشته باشید که فرایند Notepad از سه صفحه پیوندی از آدرس های مجازی استفاده می‌کند، با شروع از آدرس 0x7F7'93950000. اما این سه صفحه مجاور آدرس‌های مجازی به صفحات غیر مستقیم در حافظه فیزیکی نقش می‌شود. همچنین توجه کنید که هر دو فرایند با استفاده از یک صفحه از حافظه مجازی شروع از 0x7F7'93950000 استفاده می‌کنند، اما آن صفحات مجازی به صفحات مختلف حافظه فیزیکی نقش می‌شوند. فضای کاربر و فضای سیستم: فرایند‌هایی مانند Notepad.exe و MyApp.exe در حالت کاربر اجرا می‌شوند. اجزاء اصلی سیستم‌عامل و بسیاری از درایور‌ها بیشتر در حالت کِرنل مورد استفاده قرار می‌گیرند. هر فرایندِ حالت کاربر دارای فضای آدرس خود است ، اما تمام کد‌هایی که در حالت هسته اجرا می‌گردند، یک فضای آدرس مجزا به نام فضای سیستم دارند (دارای فضای آدرس مشترک هستند) . فضای آدرس مجازی برای فرآیند کاربر حالت فعلی کاربر، user space نامیده می‌شود. در ویندوز 32 بیت، فضای آدرس مجازی موجود در دسترس 2 به توان 32 بایت (4 گیگابایت) است. معمولاً 2 گیگابایت کمتر برای فضای کاربر می‌باشد و ۲ گیگابایت بالاتر برای فضای سیستر در نظر گرفته می‌شود. در ویندوز 32 بیتی شما میتوانید گزینه ای (در هنگام بوت شدن) را مشخص کنید که بیش از 2 گیگابایت برای فضای کاربر در دسترس باشد . در نتیجه آدر مجازی کمتری در دسترس سیستم قرار می‌گیرد. شما می‌توانید حجم فضای کاربر را تا 3 گیگا بایت افزایش دهید ، در این صورت فقط 1 گیگ فضا برای سیستم باقش می‌ماند. در ویندوز های 64 بیتی مقدار فضای آدرس مجازی 2 به توان 64 بایت (16 اگزابایت) می‌باشد . اما تنها بخش کوچکی از این محدوده استفاده میگردد محدوده 8 ترابایت از 0x000'00000000 تا0x7FF'FFFFFFFF برای فضای کاربر استفاده می‌شود و بخش هایی از 248 ترابایت از 0xFFFF0800'00000000 تا 0xFFFFFFFF'FFFFFFFF برای فضای سیستم استفاده می‌گردد. کُدِ در حال اجرا در حالت کاربر دسترسی به فضای کاربر دارد، اما دسترسی به فضایِ سیستم ندارد‌. این محدودیت باعث می‌شود که کد کاربر حالت خواندن یا تغییر ساختار داده های محافظت شده سیستم عامل را نداشته باشد. کد در حالِ اجرا در حالت هسته دارای دسترسی به فضای کاربر و فضای سیستم می‌باشد. درایور‌ها (راه‌انداز‌هایی) که در حالت هسته اجرا می‌شوند باید در نوشتن یا خواندن در فضای آدرس کاربر به دلایل زیر بسیار محتاط باشد: یک برنامه یوزر مُد (حالت کاربر)، یک در خواست برای خواندن برخی از داده‌ها را به یک دستگاه می‌فرستد. این برنامه آدرس اولیه یک بافر برای دریافت داده ها را فراهم می‌کند. یک دستگاه روتینِ درایور در حالت اجرا در حالت هسته‌، عملیات خواندن را شروع می‌کند و کنترل را به تماس گیرنده خود بازمی‌گرداند سپس اینتراپت دستگاه هر نخ (ترد) را که در حال اجرا است را قطع می‌کند. در این مرحله، درایور نباید دادهها را به آدرس اولی‌ها ارسال کند که در برنامه کاربر، در قسمت اول به آن اشاره شد. این آدرس در فضای آدرس مجازی فرایند است که درخواست را آغاز کرده است، که به احتمال زیاد همانند فرایند فعلی نیست. مخازن (استخر حافظه) صفحه‌بندی شده و صفحه‌بندی نشده (Paged pool and Nonpaged pool) در فضای کاربری، تمام صفحات حافظه فیزیکی را می‌توان به عنوان یک فایل دیسک به صورت صحیح برگرداند‌. در فضای سیستم، برخی صفحات فیزیکی می‌توانند از بیین بروند و برخی نیز نمی‌توانند. فضای سیستم دارای دو منطقه برای تخصیص حافظه پویا می‌باشد : paged pool و nonpaged pool. در حالت paged pool حافظه می‌تواند به صورت فایل (در صورت نیاز) به دیسک منتقل گردد. در حالت nonpaged pool هرگز حافظه نمی‌تواند به دیسک منتقل گردد. کتابخانه‌ی پیوند پویا و فایل‌های اجرایی (DLL و PE) در این قسمت کمی با ساختار فایل های اجرایی و بخصوص DLL ها آشنا می‌شویم. در خلاصه ترین حالت می‌توان گفت Dynamic link library نام کتابخانه‌هایی است که توسط برنامه ها استفاده می‌شوند و توسط مایکروسافت پیاده سازی شده ( که اغلب دارای پسوند dll می‌باشند). این فایل ها همانند ساختار فایل های exe در ویندوز دارای ساختار (PE (Portable Executable می‌باشد. این کتابخانه‌ها می‌توانند شامل کد و داده و منابع (ریسورس‌ها) باشند. یکی از مزایای فایل های dll این است که یک بار در حافظه بارگذاری می‌شود و می‌تواند توسط چندین برنامه مورد استفاده قرار گیرد (به صورت مجازی برای هر برنامه کپی می‌شود). می‌توان dll ها را در موقه نیاز در برنامه بارگذاری کرد و هر جا که دیگر مورد نیاز نبود آن را خالی (Unload) کرد. از طرفی دیگر می‌توان از آن برای استفاده از برنامه های قابل به‌روز‌رسانی نیز استفاده کرد به این صورت که می‌توان آیکن‌ها ، فونتها و کدهایی که در هسته اصلی برنامه جایگاهی ندارند را درون dll ها قرار داد و در هنگام به‌روز‌رسانی تنها این dll ها را تعویض کرد. هر فایل اجرایی جدا از کدها و دادههای خود می‌تواند اطلاعات را از خارج از خود و از dll بگیرد. در هر فایل pe بخشی از هدر فایل، شامل آدرس جدول آدرس وارد کردن (Import) می‌شود که اطلاعات موجود در آن، آدرس توابعی که از dll ها فراخوانی می‌شود را در خود نگه داری می‌کنند ( البته این آدرس ها با پایه‌ی آدرس dll ترکیب می‌شوند که در تصویر دوم هم قابل مشاهده است). تصویر زیر خلاصه‌ای ار هدر فایلهایی با ساختار PE می‌باشد. در این عکس import adress table حاوی آدرس iat در برنامه می‌باشد. شکل زیر یک توضیح کلی تر و بهتر در اختیار ما می‌گذارد. در این شکل می‌توان iat را بین دو بخش کد و داده ببینید. نمونه ای از فراخوانی یکی از توابع dll ها را در زیر می‌توان مشاهده کرد. این تصویر کد اسمبلی یک برنامه می‌باشد. مثال های کاربردی: مثال اول: در مثال اول یک dll ساخته و آن را با rundll32.exe اجرا کنید. از قسمت پروژه‌ جدید (New project) در قسمت سی‌پلاس‌پلاس پروژه ای از نوع win32project بسازید. در صفحه باز شده Next را بزنید. dll را انتخاب کرده و سپس تیک Empty project را بزنید و پروژه را بسازید. سپس به پروژه خود یک فایل cpp اضافه کنید و کد‌های زیر را در آن بنویسید: //[dll01.dll] #include <windows.h> extern "C" __declspec (dllexport) void __cdecl hello() { ::MessageBox(0, L"hello world", 0, 0); } BOOL APIENTRY Dll(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { return TRUE; } برنامه را کامپایل کنید، سپس cmd را باز کرده و دستور زیر را در آن تایپ کنید . (در آدرسی که dll قرار دارد دستور را اجرا کنید یا این که آدرس کامل dll را به آن بدهید) c:\rundll32.exe dll01.dll,hello شکل کلی استفاده از این دستور: RUNDLL32.EXE <dllname>,<entrypoint> <optional arguments> با اجرای این دستور پنجره‌ای را می‌بینید که در آن پیغام موجود در dll را چاپ می‌کند. مثال دوم: در این مثال‌، دی‌ال‌ال (dll) ای که در مثال قبل ساختید را در یک برنامه دیگر با زبان c++ ایجاد و بعد از اتمام کار، آن را آن بارگذاری کنید. کُد برنامه مورد نظر به صورت زیر خواهد بود: #include <windows.h> #include <stdio.h> typedef void(__cdecl *MYPROC)(); int main(void) { HINSTANCE hinstLib; MYPROC ProcAdd; BOOL fFreeResult, fRunTimeLinkSuccess = FALSE; // Get a handle to the DLL module. hinstLib = LoadLibrary(TEXT("c://dll01.dll")); // If the handle is valid, try to get the function address. if (hinstLib != NULL) { ProcAdd = (MYPROC)GetProcAddress(hinstLib, "hello"); // If the function address is valid, call the function. if (NULL != ProcAdd) { printf("dll is loaded\n"); fRunTimeLinkSuccess = TRUE; (ProcAdd)(); } // Free the DLL module. fFreeResult = FreeLibrary(hinstLib); if (fFreeResult && ProcAdd) { printf("dll is Unloaded\n"); } else if (!fFreeResult && ProcAdd) { printf("error , dll is not Unload\n"); } } // If unable to call the DLL function, use an alternative. if (!fRunTimeLinkSuccess) { printf("Message printed from executable\n"); } system("pause"); return 0; }
  48. 1 امتیاز
    در جلسه قبل کتابخانه را دانلود و نصب کردیم و برای تست کدی را اجرا کردیم که حاصل ان نمایش یک تصویر در یک پنجره بود اما درباره ی کلاس Matو همچنین توابع imread،imshow،waitKey توضیحی ندادیم کلاس Mat یک ماتریس است که تا هر چند بعد را در خود ذخیره میکند تابع imread برای بارگذاری تصویر است که تصویر را خوانده و در قالب یک ماتریس برمیگرداند که اینجا تصویر دو بعد دارد RowوColumn وقتی تصویر بارگذاری شد باید در یک ماتریس ذخیره شود پس به یک ماتریس نیاز داریم که همونطور که دیدید تعریف کردیم تابع imshow برای نمایش تصویر است ورودی اول این تابع نام پنجره است و ورودی دوم یک InputArray است که یک ورودی از ارایه از ما میخواهد در اینجا ما از هر کلاس کانتینری یا حتی ارایه معمولی هم بدهیم قبول میکند چون از ما یک ورودی ارایه میخواهد فرقی نمی کند که این ورودی چگونه و از چه نوعی باشد اما چون این یک تصویر را نمایش میدهد باید ورودی بدهیم که حاوی داده های تصویر باشد نه چیز دیگری پس به این موضوع هم دقت کنید تابع waitKey منتظر می ماند تا بعد از نمایش تصویر و فشردن کلیدی از صحفه کلید به برنامه پایان دهد. در این جلسه به کلاس Image Filtering توابع کاربری ان میپردازیم ابتدا چند تابع این کلاس را توضیح خواهم داد و سپس از هر کدام یک مثال خواهم زد. چند تابع که این کلاس دارد عبارتند از:bilateralFilter،blur،boxFilterLaplacian،medianBlur این چند تابع هر کدام فیلتری رو تصویر اعمال میکنند در هنگام دادن ورودی به توابع به ان چیزی که میخواهد توجه کنید و مقادیر صحیح را به ورودی توابع بدهید که به خطا مواجه نشوید در غیر اینصورت به مشکل برمیخورید. تابع bilateralFilter: یک محدوده ی مشخص شده توسط پارامتر سوم را با اندازه های داده شده در پارامتر های چهارم و پنجم را که مشخص کنند رنگ و فاصله هستند ترکیب میکند پارامتر سوم مشخص میکند در چه محدودهای از پیکسل های تصویر شروع به ترکیب رنگ در فاصله ی داده شده در پارامتر پنجم کند این محدوده اگر کوچکتر از پارامتر های چهارم و پنجم باشد بخشی از پیکسلها را در برمیگیرد اگر در پارامتر های چهارم و پنجم اندازه ی بیش از حد بدهیم و اندازه ی پارامتر سوم بیش از حد کوچک باشد تصویر به حالت کدر در می اید در غیر اینصورت اگر پارامتر ها بدرستی تنظیم شده باشند یک ترکیب رنگ زیبا در تصویر را خواهیم داشت این ترکیب رنگ در خود تصویر است به مثال زیر دقت کنید: #include <opencv2\opencv.hpp> #include <Windows.h> using namespace cv; int main() { Mat output_image; Mat image_read = imread("C:\\Users\\Mohamad4030\\Desktop\\beautiful-sunset-sunrise-photo-5.jpg", IMREAD_COLOR); bilateralFilter(image_read, output_image, 100, 300, 500); imshow("befor", image_read);//befor Filtering imshow("after", output_image);//after Filtering ShowWindow(GetConsoleWindow(), SW_HIDE); waitKey(0); } حاصل اجرای کد بالا به صورت زیر خواهد بود: تابع blur: با دریافت عرض و ارتفاع و موقعیت xوy در تصویر حالت تاری را به وجود می اورد باید دقت کنید موقعیت باید به همان اندازه مشخص شود که در عرض و ارتفاع مشخص میشود بیشتر از عرض و ارتفاع باشد برنامه متوقف خواهد شد چون نباید بزرگتر از عرض و ارتفاع باشد هر چه موقعیت بیشتر باشد تاری در ان موقعیت بیشتر میشود به مثال زیر دقت کنید: #include <opencv2\opencv.hpp> #include <Windows.h> using namespace cv; int main() { Mat output_image; Mat image_read = imread("C:\\Users\\Mohamad4030\\Desktop\\beautiful-sunset-sunrise-photo-5.jpg", IMREAD_COLOR); //bilateralFilter(image_read, output_image, 100, 300, 500); blur(image_read, output_image, Size(100, 100),Point(99,99)); imshow("befor", image_read);//befor Filtering imshow("after", output_image);//after Filtering ShowWindow(GetConsoleWindow(), SW_HIDE); waitKey(0); } حاصل اجرای کد بالا به صورت زیر خواهد بود: برای بهتر متوجه شدن این تابع چند بار موقعیت xوy را تغییر دهید و نتیجه را ببینید. تابع boxFilter: با مشخص کردن عمق برای تصویر و عرض و ارتفاع و موقعیت xوy ان منطقه از تصویر را با توجه به مقداری که برای عمق تصویر داده میشود تغییرمیدهد در بعضی موارد که به عنوان مثال عمق تصویر 0 باشد تصویر در همان حالت خود باقی میماند و درواقع کار تابع blur را انجام میدهد در پارامتر اخر میتوانید حالت border ان را تایین کنید که میتواند توسط خود نوع های شمارشی مورد استفاده قرار گیرد که جایی که فیلتر شده است خط مرزی ان رسم شود به مثال زیر دقت کنید: #include <opencv2\opencv.hpp> #include <Windows.h> using namespace cv; int main() { Mat output_image; Mat image_read = imread("C:\\Users\\Mohamad4030\\Desktop\\0.047489001316013508_pixnaz_ir.jpg", IMREAD_COLOR); //bilateralFilter(image_read, output_image, 100, 300, 500); boxFilter(image_read, output_image, 5, Size(1, 1)); imshow("befor", image_read);//befor Filtering imshow("after", output_image);//after Filtering ShowWindow(GetConsoleWindow(), SW_HIDE); waitKey(0); } حاصل اجرای کد بالا به صورت زیر خواهد بود: تابع Laplacian: با دریافت عمق سایز پیکسل مقیاس برای روشنایی و مقدار دلتا تصویر را به حالت های مختلف درمی اورد دقت داشته باشید برای دریافت نتیجه مطلوب باید مقیاس و دلتا هر دو مقداری داشته باشند نداشتن مقدار برای هر کدام تصویر را روشن و تیره میکند به مثال زیر دقت کنید: #include <opencv2\opencv.hpp> #include <Windows.h> using namespace cv; int main() { Mat output_image; Mat image_read = imread("C:\\Users\\Mohamad4030\\Desktop\\c9ac_d2ynkbk.jpg", IMREAD_COLOR); //bilateralFilter(image_read, output_image, 100, 300, 500); //boxFilter(image_read, output_image, 5, Size(1, 1)); Laplacian(image_read, output_image, 0,1,10.0,100.0); imshow("befor", image_read);//befor Filtering imshow("after", output_image);//after Filtering ShowWindow(GetConsoleWindow(), SW_HIDE); waitKey(0); } حاصل اجرای کد بالا به صورت زیر خواهد بود: با تعغیر دادن مقیاس و دلتا نتایج دیگری بدست می اید همچنین عمق و سایز پیکسل با تعغیر رو تصویر تاثیر میگذارند. تابع medianBlur: با دریافت سایز در پارامتر سوم تصویر را بصورت خاصی کدر میکند که هرچه سایز بیشتر باشد تصویر کارتونی به نظر میرسد به مثال زیر دقت کنید: #include <opencv2\opencv.hpp> #include <Windows.h> using namespace cv; int main() { Mat output_image; Mat image_read = imread("C:\\Users\\Mohamad4030\\Desktop\\c9ac_d2ynkbk.jpg", IMREAD_COLOR); //bilateralFilter(image_read, output_image, 100, 300, 500); //boxFilter(image_read, output_image, 5, Size(1, 1)); medianBlur(image_read, output_image, 17); imshow("befor", image_read);//befor Filtering imshow("after", output_image);//after Filtering ShowWindow(GetConsoleWindow(), SW_HIDE); waitKey(0); } حاصل اجرا کد بالا بصورت زیر خواهد بود:
  49. 1 امتیاز
    کتابخانه‌ی اوپن سی اِل مخفف Open Computing Language بستری برای برنامه‌هایی که قرار است بر سکو‌های ناهمگن یا تکیه بر پردازنده‌های مرکزی و پردازنده‌های گرافیکی و سایر پردازنده‌ها اجرا شوند. این کتابخانه دارای یک زبان بر پایه‌ی C99 و C++11 برای نوشتن کرنل‌ها و همچنین رابط‌های برنامه‌نویسی برای تعریف و پس از کنترل بستر استفاده شوند را دارا است. این کتابخانه چند‌پردازندگی را با استفاده از روش‌های وظیفه محور (Task-Based) و داده محور (Data-Based) پشتیبانی می‌کند. اوپن سی اِل توسط هر دو شرکت AMD/ATI و Nvidia پذیرفته شده است. در طراحی اوپن سی اِل، مقدار زیادی از رابطه‌های پردازشی با Cuda و رقیب آن، مایکروسافت دایرکت کامپیوت (Direct-Compute) به اشتراک گذاشته شده است. پیاده سازی‌های مربوطه از طرف Altea, AMD, Apple صورت گرفته شده است که در این میان OpenCL همراه با OpenGL به نفع Metal2 منسوخ شده اند. همچنین IBM, Imagination, Intel, Nvidia, Qualcomm, Samsung, Vivante, Xilinx و Ziilabs آن را پذیرفته‌اند. این کتابخانه یکی از قدرتمند ترین پلتفرم‌های موجود در بازار در مقابل DirectX می‌باشد گه از سوی کمیته‌ی Khronos Group اعلام شده است که پا به پای DirectX ه فعالیتش ادامه می‌دهد. جالب است بدانید نسخه‌های جدید این کتابخانه با قدرت بسیار زیادی بر روی PS4 و PS4 Pro استفاده می‌شوند. از آنجایی که PS4 از معماری GCN استفاده می‌کند، قابلیت پشتیبانی از DiectX 12 نیز برای آن فراهم شده است. بهتر است بدانید توسعه اصلی این پلتفرم توسط اپل انجام شده است که در حال حاضر توسط کمیته‌ی Khronos Group اداره می‌شود که بر روی طیف وسیعی از سخت افزار‌های روز و کارت گرافیکی‌های محتلف گرفته تا پردازنده‌های موجود پشتیبانی می‌شود. قدرت روز افزون اوپن سی اِل در حال افزایش است و شاید اگر قدرت و سرمایه‌ی مایکروسافت نبود، OpenCL سلطان بی چون و چرای بازار می‌شد. کودا با وجود انکار انویدیا، فریم ورکی است اختصاصی که در بسیاری از محصولات مورد استفاده قرار می‌گیرد. انویدیا تلاش می‌کند رقبایش را به استفاده از کودا وادار کند، اما تلاشش نتیجه بخش نبوده و می‌بینم که از این فریم ورک بیشتر در توسعه محصولات خودش استفاده می‌شود. از طرفی می‌توان ادعا کرد که Direct Compute هم اختصای است. چون فقط بر روی ویندوز و دایرکت اِکس ۱۱ به بالا اجرا می‌شود. اما OpenCL منبع باز است و بسیاری از شرکت‌های بزرک از جمله Nvidia از آن پشتیبانی می‌کنند. جهت نصب و راه اندازی این کتابخانه برای پردازنده‌های Intel به این بخش مراجعه کرده و نسخه‌ی Amd را در این بخش و برای Nvidia از این صفحه دریافت و استخراج نمایید. این کتابخانه در قالب SDK شامل include و lib تحت تو معماری x86 و x64 می‌باشد که باید در محیط توسعه‌ی نرم‌افزاری خود آن را معرفی کنید. در محیط Qt Creator طبق آموزش‌های قبل اقدام کنید. با توجه به اینکه ما SDK مربوطه را در مسیر C:/IntelOpenCL/sdk استخراج کرده‌ایم، کُد فایل .pro به صورت زیر خواهد بود: LIBS += -L$$PWD/../../../../../Intel/OpenCL/sdk/lib/x86/ -lOpenCL INCLUDEPATH += $$PWD/../../../../../Intel/OpenCL/sdk/include DEPENDPATH += $$PWD/../../../../../Intel/OpenCL/sdk/include جهت آزمایش عملکرد کتابخانه توجه داشته باشید که فایل‌های هدر در پلتفرم macOS در پوشه‌ی OpenCL و در محیط‌های ویندوز و لینوکس در مسیر CL موجود می‌باشند. #ifdef __APPLE__ #include <OpenCL/opencl.h> #else #include <CL/cl.hpp> #endif در ادامه کد زیر نتیجه‌ی جمع دو آرایه با یکدیگر را تحت OpenCL اجرا خواهد گرد: #include <iostream> #include <vector> #ifdef __APPLE__ #include <OpenCL/opencl.h> #else #include <CL/cl.hpp> #include <CL/opencl.h> #endif using namespace std; int main(){ //get all platforms (drivers) std::vector<cl::Platform> all_platforms; cl::Platform::get(&all_platforms); if(all_platforms.size()==0){ std::cout<<" No platforms found. Check OpenCL installation!\n"; exit(1); } cl::Platform default_platform=all_platforms[0]; std::cout << "Using platform: "<<default_platform.getInfo<CL_PLATFORM_NAME>()<<"\n"; //get default device of the default platform std::vector<cl::Device> all_devices; default_platform.getDevices(CL_DEVICE_TYPE_ALL, &all_devices); if(all_devices.size()==0){ std::cout<<" No devices found. Check OpenCL installation!\n"; exit(1); } cl::Device default_device=all_devices[0]; std::cout<< "Using device: "<<default_device.getInfo<CL_DEVICE_NAME>()<<"\n"; cl::Context context({default_device}); cl::Program::Sources sources; // kernel calculates for each element C=A+B std::string kernel_code= " void kernel simple_add(global const int* A, global const int* B, global int* C){ " " C[get_global_id(0)]=A[get_global_id(0)]+B[get_global_id(0)]; " " } "; sources.push_back({kernel_code.c_str(),kernel_code.length()}); cl::Program program(context,sources); if(program.build({default_device})!=CL_SUCCESS){ std::cout<<" Error building: "<<program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(default_device)<<"\n"; exit(1); } // create buffers on the device cl::Buffer buffer_A(context,CL_MEM_READ_WRITE,sizeof(int)*10); cl::Buffer buffer_B(context,CL_MEM_READ_WRITE,sizeof(int)*10); cl::Buffer buffer_C(context,CL_MEM_READ_WRITE,sizeof(int)*10); int A[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; int B[] = {0, 1, 2, 0, 1, 2, 0, 1, 2, 0}; //create queue to which we will push commands for the device. cl::CommandQueue queue(context,default_device); //write arrays A and B to the device queue.enqueueWriteBuffer(buffer_A,CL_TRUE,0,sizeof(int)*10,A); queue.enqueueWriteBuffer(buffer_B,CL_TRUE,0,sizeof(int)*10,B); //run the kernel //alternative way to run the kernel cl::Kernel kernel_add=cl::Kernel(program,"simple_add"); kernel_add.setArg(0,buffer_A); kernel_add.setArg(1,buffer_B); kernel_add.setArg(2,buffer_C); queue.enqueueNDRangeKernel(kernel_add,cl::NullRange,cl::NDRange(10),cl::NullRange); queue.finish(); int C[10]; //read result C from the device to array C queue.enqueueReadBuffer(buffer_C,CL_TRUE,0,sizeof(int)*10,C); std::cout<<" result: \n"; for(int i=0;i<10;i++){ std::cout<<C[i]<<" "; } return 0; } نتیجه خروجی جمع دو آرایه با یکدیگر و همچنین شناسایی پلتفرم‌های قابل پشتیبانی در OpenCL: Using platform: Intel(R) OpenCL Using device: Intel(R) HD Graphics 4400 result: 02435768109
  50. -1 امتیاز
    تکلیف مشخص نمیکنم منظورم این بود که توضیح لازم دارم و هم چنین خودم سعی کردم متوجه بشم یعنی قبل از سوال کردن سرچ کردم و متوجه نشدم پس اگه هر لینک بدی من قابل (befor) از این که سوال و بپرسم اون لینک و خوندم مرسی بابت جواب
این صفحه از پرچمداران بر اساس منطقه زمانی تهران/GMT+03:30 می باشد
×
×
  • جدید...