- Секрети середовища розробки Visual Studio
- Закладки
- препроцесор
- Пошук
- видалення тексту
- Операції з рядками і словами
- Переміщення по тексту
- Операції з сентенціями
- виділення
- повтор дій
- Корисні макроси
- Самостійна реалізація функцій з аргументами за замовчуванням в класичному Сі
Улюблені книги: [ класика ] [ Бази даних ] [ Internet / WWW ] [ мережі ] [ програмування ] [ UNIX ] [ Windows ] [ Безпека ] [ графіка ] [ Software Engineering ] [ ERP-системи ] [ Hardware ]
Секрети середовища розробки Visual Studio
(Стаття була опублікована в журналі "Програміст")Сучасні програмні інтерфейси помітно потіснили, якщо не сказати витіснили, документацію, яка, на думку більшості користувачів, нікому крім "ламеров" вже не потрібна. Призначення більшості пунктів меню інтуїтивно зрозуміло і так, а, якщо навіть і незрозуміло, його неважко з'ясувати експериментально.
Насправді ж, меню - лише верхівка айсберга, а велика частина функціональних можливостей багатьох додатків прихована під водою. Просунуті програмні пакети, такі як, наприклад, Microsoft Visual Studio містять тисячі команд, і, якби всі вони були "втиснуті" в меню, його б розміри зросли щонайменше до Місяця. Ось і доводиться поміщати в меню лише найбільш важливі (з точки зору розробників) команди, приховуючи інші від очей користувача.
Не варто думати, що всі приховані команди - нікому не потрібний баласт. Серед них причаїлося чимало справжніх коштовностей, що значно полегшують життя програмісту.
Дана глава присвячена маловідомим, але надзвичайно корисним секретам середовища розробки Visual Studio 6.0. Оскільки, це середовище так само неосяжна, як і світ, розповісти про всі можливості в рамках однієї статті просто неможливо. Тому, обмежимося лише вбудованим редактором текстів - найважливішим компонентом будь-якого середовища розробки.
Маленьке зауваження мимохідь: якщо ви прийшли на Windows з UNIX і вам жахливо бракує можливостей тих середовищ розробки - ця глава для вас! Все, що було в UNIX, є і в Windows, тільки приховано від сторонніх очей. Але ми-то з вами не сторонні, правда? :-)
Закладки
Visual Studio підтримує два типи закладок. Одні перераховуються в діалоговому вікні "Bookmark", доступному з меню "~ Edit \ Bookmarks", а інші відзначаються блакитним квадратиком ліворуч від "закладеної" рядки (див. Рис. 1.1). Причому перші і останні ніяк не пов'язані між собою - додавання закладки "блакитного квадратика" не змінює вмісту списку "Bookmark" і навпаки. Більш того, управління закладками "блакитних квадратиків" взагалі не є з системи меню! (Правда, закладками можна управляти через панель інструментів "Edit", але за замовчуванням вона на екрані не відображається). Щоб встановити таку закладку підведіть курсор до відповідної рядку і натисніть "гарячу" клавішу <Ctrl-F2>. Повторне натискання видаляє закладку.
Для видалення всіх закладок "блакитних квадратиків" передбачена команда BookmarckClearAll, доступна через комбінацію клавіш <Shift-Ctrl-F2>. Закладки, призначені через меню "Edit \ Bookmarks" (<Alt-F2>) при цьому не видаляються.
Для швидкого пошуку закладок можна скористатися як перегортання вперед: клавіша <F2> переміщує курсор до наступної закладки (при цьому курсор не обов'язково повинен знаходиться на закладці), так і перегортання назад: натискання клавіш <Shift-F2> переміщують курсор до попередньої закладці.
До речі, при контекстному пошуку підрядка можна автоматично позначати все, що містять її рядки, "блакитними" закладками. Для цього в діалоговому вікні "Find" (<Ctrl-F>) замість "ОК" натисніть кнопку "Mark All". Повторний запитом не знайдено видаляє старих закладок, але додає до них нові. Причому, видалити закладки, користуючись однією лише системою меню, неможливо! Але ми-то з вами вже знаємо, що такі закладки видаляються або натисканням <CtrlF2>, або натисканням <ShiftCtrlF2>.
Секрети закладок на цьому не закінчуються. Якщо вас дратує, що для додавання нової Bookmark-закладки необхідно виконувати цілий ряд операцій (натискати <Alt-F2>, вводити ім'я закладки, шукати кнопку "Add"), - скористайтеся командою "BookmarkDrop (Epsilon)", який робить все це автоматично! З незрозумілих причин, їй не відповідає ніяка клавишная комбінація, тому її доводиться призначати самостійно. Це можна зробити, наприклад, так. В меню "Tools" виберіть пункт "Customize", в діалоговому вікні перейдіть до закладки "Keyboard" і в випадаючому боксі "Category" виберіть категорію "Edit". Тепер у вікні "Commands" знайдіть команду "BookmarkDrop (Epsilon)", перемістивши курсор у вікно "Press new shortcut key" та натисніть комбінацію клавіш, яку вам буде зручно виконувати цю команду. Якщо ця комбінація вже використовується - в поле "Currently assigned" з'явиться назва її власника, в іншому випадку - "unassigned". Для підтвердження призначення нової клавішній комбінації натисніть кнопку "Assign".
Тепер при натисканні вашої "гарячої" клавіші в "Bookmark" будуть автоматично додаватися закладки, нумеровані в прядки зростання від нуля до дев'яти. Якщо виникне необхідність встановити закладку з яким-небудь конкретним номером, скористайтеся командами "BoolmarkDrop1 (Brief)", "BoolmarkDrop2 (Brief)" "BoolmarkDrop10 (Brief)". За замовчуванням їм так само не відповідає ніяка клавишная комбінація, і ви повинні призначити її самостійно.
Дуже корисна команда "BookmarkJumpToLast (Epsilon)", циклічно перегортувалися Bookmark-закладки в порядку убування їх номерів. Їй, як і попереднім командам, призначати "гарячу" клавішу доводиться самостійно.
Рис 1.1 Закладка "блакитного квадратика"
препроцесор
Кожен, хто працював з лістингами (особливо чужими), знає: яку сум'яття вносять директиви умовної компіляції. Припустимо, зустрічається в тексті директива "#ifdef _A_". Як визначити - які рядки програми відносяться до її тіла, а які ні? Теоретично в цьому немає нічого складного - досить знайти директиву "#else" або "#endif", але як її знайти? Контекстний пошук тут непридатний. Оскільки директиви умовної компіляції можуть бути вкладеними, немає ніяких гарантій, що найближчий знайдений "#endif" або "#else" відноситься до тієї ж самої директиві "#ifdef". Доводиться перегортати програму вручну, подумки відстежуючи всі вкладення і переходи. Однак це, по-перше, дуже повільно, а по-друге, так легко "прогавити" кілька директив, особливо якщо вони розділені великою кількістю рядків.
На щастя, Visual Studio вміє трассіровать директиви умовної компіляції в обох напрямках. Правда, по абсолютно незрозумілим мотивами ця можливість не афішується і взагалі прихована від сторонніх очей.
Якщо курсор знаходиться в тілі однієї з гілок директиви умовної компіляції (т. Е. Або гілки "#if #else", або "#else #endif", або "#if #endif"), то натисканням <CtrlK> ми перемістимося в її кінець! Повторне натискання призведе до переходу або на наступну гілку, або (якщо поточна гілка вичерпана) - на наступну вищерозміщених директиву. Щоб уникнути плутанини звертайте увагу на рядок статусу: перехід з гілки на гілку супроводжується повідомленням: "Matching #ifdef .. # endif found", а перехід до вкладеної директиві - "Enclosing #ifdef .. # endif found". Відповідно, повідомлення "No Enclosing #ifdef .. # endif found" говорить про те, що нічого знайти не вдалося.
Для зворотного трасування (тобто проходженню ланцюжка директив від низу до верху) натисніть <CtrlJ>.
Комбінації <ShiftCtrlK> і <ShiftCtrlJ> автоматично виділяють тіло трассируемого директив, - це дуже корисно, якщо його планується копіювати в буфер або взагалі вирізати з програми.
Трасування умовних директив - це просто казка, в яку безмежно закохуєшся з перших же хвилин знайомства Вивчення SDK'шних файлів, таких, наприклад, як WINNT.H без неї просто немислимо!
#ifdef _A_ // (якщо тут натиснути Ctrl-K, ми // перемістимося в L1 // багато рядків тексту #ifdef _B_ // багато рядків тексту #else // (якщо тут натиснути Ctrl-K, ми // переместімcя в S1 // багато рядків тексту #endif // (S1 #else // (L1 // багато рядків тексту #endifЛістинг 27 Трасування директив умовної компіляції надзвичайно полегшує вивчення вихідних текстів
Пошук
Команда "FindBackwardDlg" відкриває діалогове вікно "Find", автоматично встановлюючи зворотний напрямок пошуку рядка. За замовчуванням вона не пов'язана ні з якою "гарячої" клавішею і призначити її ви повинні самостійно ( "Tools (Customize (Keyboard (Category Edit (FindBackwardDlg").
Відповідно, команда "FindForwardDlg" відкриває вікно "Find", автоматично встановлюючи прямий напрямок пошуку. Штатний виклик діалогу "Find" комбінацією <CtrlF> зберігає останнім використовується напрямок.
Команди "FindRegExpr" і "FindRegExprPrev" відкривають діалогове вікно "Find" автоматично встановлюючи галочку "Пошук регулярних виразів", причому, перша з них задає пряме, а друга - зворотний напрямок пошуку.
"Гаряча" клавіша <F3> повторює пошук попередньої підрядка не викликаючи діалог "Find", що набагато швидше.
Ще зручніше комбінація <CtrlF3>, яка шукає наступне входження виділеного тексту. Т. е. Замість того, щоб вводити шукану підрядок в діалог "Find" досить виділити її і натиснути <CtrlF3>. Відповідно, <ShiftCtrlF3> шукає наступне входження виділеного тексту в зворотному напрямку.
Пара "гарячих" клавіш <Ctrl]> і <CtrlShift]> переміщують курсор до наступної або попередньої парної дужки відповідно. Це надзвичайно корисно при розборі "монтроузних" виразів. Припустимо, у нас є вираз "(((A) + (B)) + (C))" і необхідно знайти пару другий ліворуч скобці. Підводимо до неї курсор, натискаємо <Ctrl]> і ось вона, третя дужка справа! Відповідно, <ShiftCtrl]> поверне нас на вихідну позицію назад. Таким чином, перевірка коректності вкладення дужок з рутинної праці перетворюється в приємну розвагу.
Команди "LevelUp" і "LevelDown" дуже схожі на попередні, але, по-перше, не вимагають, щоб курсор знаходився на скобці, а, по-друге, не мають власних гарячих клавіш. На мій погляд, це несправедливо і нелогічно, тому що вони набагато зручніше в роботі!
Команди "LevelCutToEnd" і "LevelCutToStart" вирізають у буфер обміну тіло вираження до наступної або попередньої парної дужки відповідно. Якщо ж вам треба не вирізати, а копіювати, то можна вдатися до невеликої хитрості - вирізати текст і тут же виконати відкат (Undo). Фокус в тому, що відкат торкається буфер обміну, але відновлює віддалений текст. Як неважко здогадатися, обидві команди "гарячими" клавішами не обтяжені, і призначати їх доведеться самостійно.
Мал. 1.2 Пошук парних дужок
"Гаряча" клавіша <CtrlD> переміщує курсор в "Find Tools" - спадаючий бокс, розташований на панелі інструментів і зберігає кілька останніх шаблонів пошуку (див. Рис. 3). Звичайно, по ньому можна клікнути і мишкою, але клавіатура дозволить зробити це швидше, без відриву рук від виробництва!
Мал. 1.3 Перехід в вікно "Find Tools"
видалення тексту
В першу чергу хотілося б звернути увагу на команду "CutAppendNext", що дозволяє додавати вирізаються фрагменти в кінець буфера обміну без затирання його вмісту. За замовчуванням вона не пов'язана ні з якою "гарячої" клавішею і призначити її ви повинні самостійно ( "Tools (Customize (Keyboard (Category Edit (CutAppendNext"). У роботі з нею є одна хитрість - сама CutAppendNext не вирізане текст в буфер, але каже редактору, що наступна операція вирізання (Cutting) тексту повинна не перезаписувати (overwrite) вміст буфера, а дописуватися (append) до нього.
Інша корисна команда "DeleteBlankLines" видаляє всі порожні рядки, розташовані під курсором, що буває корисно при "окультурення" лістингу. За умовчанням вона так само не пов'язана ні з якою комбінацією клавіш.
Її сестра - команда "DeleteHorizontalSpace" видаляє всі прогалини і символи табуляції, розташовані по обидва боки від курсора. Це буває корисно, зокрема, при видаленні зайвих відступів при переформатуванні лістингу. Як вже, ймовірно, здогадався читач, призначати гарячу клавішу на цю команду йому доведеться самостійно.
"Гаряча" клавіша <CtrlL> вирізає в буфер обміну поточний рядок цілком, а її "сестра" - <ShiftCtrlL> просто видаляє рядок, зберігаючи вміст буфера обміну незмінним.
Дві інших команди "LineDeleteToEnd" і "LineDeleteToStart" видаляють "хвіст" рядки праворуч і ліворуч від курсору відповідно.
Операції з рядками і словами
Клавишная комбінація <ShiftAltT> міняє місцями поточну і попередню рядок, що в деяких ситуаціях виявляється вельми зручніше. Її найближча родичка <ShiftCtrlT> відрізняється лише тим, що міняє місцями не рядки, а слова.
Пара команд "LineIndent" і "LineUnindent" зрушують поточний рядок на одну позицію табуляції назад і вперед відповідно. Яка від цього вигода? Чи не легше натиснути <Tab> йди <Del>? Ні, не легше, і ось чому - зазначені команди не вимагають переміщати курсор в початок рядка і виконуються з будь-якої її точки, що, погодьтеся, відчутно економить час.
Команда "IndentToPrev" вирівнює поточний рядок за образом і подобою попередньої, що значно спрощує форматування лістингу. Її найближча родичка - "IndentSelectionToPrev", як і випливає з її назви, вирівнює відразу весь виділений блок, що ще зручніше!
Переміщення по тексту
Команда "End (Brief)" циклічно переміщається до кінця поточної лінії, нижньому рядку в вікні і, нарешті, останньому рядку тексту. Можливість швидкого переміщення до нижньої рядку вікна, дійсно, дуже зручна, тому, має сенс призначити цій команді свою "гарячу" клавішу. ( "Tools (Customize (Keyboard (Category Edit (End (Brief)").
Команда "Home (Brief)" дуже схожа на попередню за тим винятком, що циклічно переміщається не вниз, а вгору. За замовчуванням їй так само не відповідає ніяка "гаряча" клавіша.
Комбінації <CtrlСтрелка вгору "і" CtrlСтрелка вниз> переміщають текст у вікні відповідно вгору і вниз, зберігаючи положення курсора, по крайней мере, до тих пір, поки він не досягне останнього рядка вікна. Це зручно при перегляді тексту програми - щоб побачити наступну рядок вам не обов'язково через все вікно гнати курсор вниз (вгору), як в звичайному редакторі.
"Гаряча" клавіша <F4> переміщує курсор до наступного рядка, що містить помилку і відзначає її чорною стрілкою. Відповідно, <ShiftF4> переміщує курсор до попередньої "помилковою" рядку.
Мал. 1.4 Навігація по помилках
Операції з сентенціями
"Гаряча" клавіша <ShiftAltL> видаляє весь текст, розташований праворуч від курсора до наступної сентенції (порожнього рядка). Якщо порожні рядки вставлені в лістинг "з розумом", - ця операція може виявитися досить корисною.
Команди "SentenceLeft" і "SentenceRight" переміщають курсор на наступну і попередню сентенцію відповідно.
виділення
"Гаряча" клавіша <F8> включає режим виділення тексту, що рівносильно утриманню <Shift>. Повторне натискання на <F8> вимикає режим виділення. Зручно при виділенні великих блоків тексту, - чи не затікає палець, раніше утримує <Shift>.
Ще цікавіше комбінація <ShiftCtrlF8>, що дозволяє виділяти вертикальні блоки тексту, що дозволяє, зокрема, одним махом видалити вертикальну рядок коментарів.
повтор дій
Для багаторазового виконання деякої операції, скажімо, вставки тисячі символів "зірочки", абсолютно нема чого кидати цеглу на клавішу "*" - досить скористатися командою "SetRepeatCount", яка встановлює, скільки разів слід наступної виконуваної операції. Кількість повторів задається або з цифрової клавіатури, або повторними викликами "SetRepeatCount", при цьому кількість повторів буде кожен раз людина розмножуватись на поверхні чотири. Чи не правда здорово ?!
Команди "SetRepeatCount0" "SetRepeatCount9" змінюють значення лічильника повторів від нуля від дев'яти відповідно.
Корисні макроси
Разом з Visual Studio поставляється кілька зразків макросів, які можуть бути використані не тільки для вивчення Visual Basic'а, але і як самостійні утиліти. Натисніть <ShiftAltM>, потім в спадаючому боксі "Macro File" виберіть "SAMPLE" і в списку "Macro Name" з'явиться список доступних макросів.
В першу чергу хотілося звернути увагу на макрос "OneTimeInclude", одним помахом руки додає в заголовки програми код, що запобігає його повторне включення, що, погодьтеся, дуже зручно:
#ifndef __IDD_xxx_ #define __IDD_xxx_ // Текст програми #endif // __ IDD _xxx_Лістинг 28 Використання макросу OneTimeInclude для запобігання повторного включення заголовних файлів в програму
Дуже корисна і пара макросів "ifdefOut" і "ifndefOut", огороджувальних виділений текст директив умовної компіляції "#ifdef" і "#idndef" відповідно. Умова компіляції запитується автоматично в діалоговому вікні. Начебто дрібниця, а як економить час!
Макрос "ToggleCommentStyle" змінює в виділеному блоці стиль коментарів з '//' на "/ * * /" і назад, що надзвичайно полегшує приведення всіх лістингів до єдиного стилю (особливо це корисно при роботі в великих програмістів колективах - свій лістинг ви оформляєте так , як вам заманеться, а потім просто переформатіруете його - і все).
Макрос "PrintAllOpenDocument", як і випливає з його назви, просто виводить всі відкриті активні документи на друк - при роботі з великою кількістю листингов ця можливість дуже зручна.
Макрос "CloseExceptActive" закриває всі активні вікна, за винятком поточного, що дуже зручно для очищення Студії від "мертвих душ", відкритих, але не використовуваних документів.
Самостійна реалізація функцій з аргументами за замовчуванням в класичному Сі
Мова Сі ++ вигідно відрізняється від свого попередника тим, що підтримує функції з аргументами за замовчуванням. Для чого вони потрібні? Переставимо собі таку ситуацію. Нехай у нас є активно використовувана функція plot (int x, int y, int color), що змальовує в заданих координатах точку заданого кольору. Припустимо, в один прекрасний момент ми усвідомлюємо, що крім координат і кольору нам життєво необхідний, скажімо, атрибут прозорості. Як бути? Реалізувати ще одну функцію, практично повторює першу (ау, метод "copy-and-paste")? Чи не занадто-то вдале рішення! Крім невиправданого збільшення розмірів програми виникне проблема синхронізації обох функцій - при виправленні помилок в першій функції, їх доведеться "відловлювати" і в другій. (Взагалі ж, в грамотно спроектованої програмі не повинно бути присутнім двох і більше ідентичних блоків).
Але чому б просто не додати ще один аргумент до функції? Справа в тому, що це вимагає внесення змін в усі інші функції, що використовують дану. А всяка зміна вже налагодженого коду загрожує появою помилок в самих непередбачуваних місцях. Ще гірше якщо така функція винесена в бібліотеку - тоді її модифікація "зрубає" безліч програм, що дуже небажано.
А давайте оголосимо атрибут прозорості аргументом за замовчуванням! Тоді, раніше написані фрагменти коду без будь-якої адоптации зможуть викликати цю функцію по "старому", навіть підозрюючи про зміну її прототипу. Завдяки цьому, ми зможемо нарощувати функціональність коду без втрати сумісності. До того ж така методика якщо не позбавляє від необхідності проектування прототипів функцій, то, у всякому разі, значно спрощує цю задачу, часто дозволяючи вирішувати її "на льоту".
На жаль, подібна тактика не може бути безпосередньо перенесена на Сі, оскільки аргументів за замовчуванням не він підтримує. Правда, Сі підтримує функції зі змінним числом аргументів, але це зовсім не те, оскільки ніякого контролю типів при цьому не виконується, що загрожує так важко впіймати помилками.
Але вихід все ж є! Автор пропонує на суд читачів свій улюблений спосіб передачі аргументів функцій, зрозуміло, без претензій на право першовідкривача. У загальних рисах суть його в тому, що набагато вигідніше передавати не самі аргументи, а покажчик на екземпляр структури, що містить в собі все необхідне функції дані.
Цей механізм, по-перше, дозволяє модифікувати "прототипи" функцій без втрати сумісності, так як опис структури міститься лише в реалізації самої функції, але не функцій її викликають. Чим, до речі, забезпечується набагато більша ступінь абстракції і гнучкості.
По-друге, передача покажчика на екземпляр структури вигідно відрізняється від передачі "простих" аргументів тим, що забезпечує спільне використання однієї області пам'яті декількома функціями, - оброблювані дані не "перепіхіваются" по ланцюжку змінних, а можуть використовуватися безпосередньо по "місцем проживання", за рахунок чого досягається помітне збільшення швидкодії програми.
По-третє, структури дозволяють оголошувати універсальні "багатопрофільні" прототипи загальні для "своїх" груп функцій. "Сверхпрототіп" одночасно включає в себе всі аргументи обраної групи функцій, а кожна з функцій вільна на свій розсуд використовувати будь-яка підмножина з них. Це ще більше абстрагує нас від деталей конкретних реалізацій і в цьому світлі групу функцій можна розглядати як один "макрооб'єкт". В результаті освоєння великих бібліотек значно спрощується. До того ж спрощується класифікація функцій, так як тепер головним відбірковим критерієм служить не її функціональність (яка часом занадто функціональна для однозначної класифікації), а цілком однозначний набір аргументів, з яким ця функція маніпулює.
Втім, при всіх достоїнствах цього методу, не позбавлений він і недоліків. Перш за все, звернення до членів структури, переданої за вказівником, вимагає додаткової витрати процесорного часу, що не найкращим чином позначається на швидкодії. Втім, величина зниження продуктивності на практиці не перевищує 0,5% - 1% і їй цілком можна знехтувати. Інший мінус - захаращення лістингу структурами, що ускладнює його розуміння. Однак до такого стилю дуже швидко звикаєш, і дискомфорт зникає сам собою.
З практичною стороною реалізації теж не все гладко. Оскільки, Сі не підтримує ініціалізації членів структури за замовчуванням, виникає проблема: як викликається функції дізнатися які саме аргументи їй передала викликає, а які містять не ініціалізований сміття? Існує кілька шляхів виходу з цього глухого кута. У частотності, можна вручну форматувати виділяється під структуру пам'ять, примусово прописуючи її "магічним" числом "значення осередки невизначено".
Звичайно, даний метод, вже хоча б в силу притаманних йому недоліків, не претендує на радикальну зміну ідеології програмування і зовсім не намеривается витісняти (і навіть потіснити) класичний механізм передачі аргументів, але в деяких випадках він все ж буває надзвичайно корисний. Сам автор цієї статті використав його в декількох великих проектах і отриманими результатами залишився задоволений. Завдяки йому кардинальні нововведення нових версій і навіть перенесення з середовища MS-DOS в операційну систему Windows обійшлися практично без модифікації вже налагодженого коду.
анотація
Статті з книги
[ Замовити книгу в магазині "Містраль" ]
Але ми-то з вами не сторонні, правда?Як визначити - які рядки програми відносяться до її тіла, а які ні?
Теоретично в цьому немає нічого складного - досить знайти директиву "#else" або "#endif", але як її знайти?
Яка від цього вигода?
Чи не легше натиснути <Tab> йди <Del>?
Чи не правда здорово ?
Для чого вони потрібні?
Як бути?
Але чому б просто не додати ще один аргумент до функції?