Примечания к статье «Как писать на С в 2016 году»
На самом деле так выглядел бы Ассемблер, если бы он был оружием, но с C тоже надо быть предельно аккуратным
От переводчика:
Данная публикация является переводом статьи-ответа на текст «How to C in 2016». Перевод последнего был опубликован мной в пятницу и вызвал, местами, неоднозначную реакцию сообщества. Наводку на данный «ответ», для поддержания обсуждения вопроса уже в рамках Хабра, дал пользователь CodeRush, за что ему отдельное спасибо.
Ранее в сети была опубликована статья «Программирование на С в 2016 году» с множеством полезных советов, среди которых, увы, были и не очень удачные идеи. Именно поэтому я решил прокомментировать соответствующие моменты. Пока я готовил новый материал, кто-то заметил, что за работу на C должны браться только ответственные программисты, в то время как безответственным хватит и других языков, в рамках которых имеется больше возможностей для совершенствования имеющихся навыков. Давайте разбираться в секретах специалистов своего дела.
Используйте отладчик
Пункт №1, который вы, наверняка, игнорируете, а зря, — запускать для каждой строки кода отладчик уровня ядра прямо на этапе написания. Если вы задействуете потенциал данного инструмента только для решения особо сложных задач, вы, определенно, допускаете ошибку.
Я имею в виду использование таких IDE, как Visual Studio, XCode, или Eclipse. Если в данном случае вы работаете только с редактором (без возможности отладки), значит, вы плохо делаете свое дело. Я упоминаю об этом нюансе, потому что очень многие пишут код в редакторах, в которых не предусмотрена функция отладки. И я не исключение.
Это важно при программировании на всех языках, но на С особенно. При повреждении памяти вам понадобится дамп структур и содержимого памяти для того, чтобы обнаружить ошибку. Почему Х выдает какое-то странное 37653? Команда отладки в стиле printf() не прояснит ситуацию, но заглянув в данные утилиты hexdump в стеке, вы обязательно поймете, как переписывался определенный объем информации.
Не забывайте об отладке своего кода
Поскольку в языке C не предусмотрена защита памяти, ошибка, допущенная в одном месте, может появиться и в другом, даже если эта часть кода не будет связана с поврежденной. Вот почему так трудно проводить отладку некоторых проблемных участков кода. В таких случаях многие программисты рвут на себе волосы, кричат: «Я не могу это исправить» и умоляют коллег помочь.
Не наступайте на те же грабли. Пару раз столкнувшись с подобными «неразрешимыми» задачами, вы научитесь писать более качественный код. Это будет самотестирующейся код, который оперативно выявляет баги, или в ходе написания будут использоваться эффективные проверочные утилиты для целых блоков данных, охватывающие пограничные случаи.
Активно защищайте код
Однажды мне довелось работать над проектом, руководители которого во избежание сбоя в программе решили ставить catch(. ) (в C ++ ) везде. Исключения и даже случаи повреждения памяти просто незаметно маскировались, и программа продолжала функционировать. Разработчикам казалось, что они снижали уязвимость кода. Они думали, что защитный стиль программирования – отличное решение.
Но это не защита, а глупость. Где логика в том, чтобы скрывать ошибки, обнаружить которые впоследствии гораздо сложнее?
Делаете по-другому. Вам нужен принцип атаки, код, который будет выявлять недочеты в максимально сжатые сроки.
Одним из способов воплотить этот подход в реальность является assert() — двойные проверочные предположения, благодаря которым вы, наверняка, все сделаете правильно. Данная функция обнаруживает баги прежде чем они навредят памяти. Я серьезно: для отладки незаметных ошибок на С я просто вставляю assert() везде, где они могут спровоцировать сбой (только не увлекайтесь предложенной командой).
Если мы говорим о кодах, лучший способ «напасть заранее» — это модульное тестирование. Как только у вас возникают сомнения, пишите модульные тесты для проверки неоднозначных параметров. Существует мнение, будто, работая на С, легко запутаться, когда изначально все идет по плану, а потом всплывают странности – для таких случаев тоже неплохо иметь в запасе подходящие тесты.
Код должен быть качественным
Что касается этого пункта, такие вещи, как модульное, регрессионное тестирование и даже фаззинг постепенно становятся нормой. Если у вас есть проект с открытым исходным кодом, вам просто необходимо запросить опцию make test, чтобы провести его качественный анализ. С ее помощью вы сможете запустить модульное тестирование кода с высоким покрытием. Такой подход считается стандартом для крупных проектов с открытым исходным кодом. Я не шучу: модульное тестирование с высоким покрытием кода должно быть отправной точкой для каждого нового проекта. Вы заметите это во всех моих серьезных разработках с открытым исходным кодом. Тут я начинаю писать модульные тексты уже на начальном этапе, причем один за другим (правда, я ленивый, и поэтому не могу похвастаться высоким покрытием кода).
Фаззинг посредством AFL – явление относительно новое, но, протестировав данный механизм, вы поймете, насколько он эффективен в процессе идентификации багов в различных проектах с открытым кодом. Язык программирования С бьет все рекорды, когда речь заходит о парсинге из вне. Раньше нередко возникали сбои в программах из-за плохо отформатированных файлов или никудышных пакетов сети. Но в 2016 году никто не станет терпеть подобную ерунду. Если вы не уверены в том, что, независимо от вводимых данных, программа, наверняка, будет работать корректно, значит, вы где-то ошиблись.
И, если вам кажется, что о качестве должен заботиться кто-то другой, вы снова заблуждаетесь.
Забудьте о глобальных переменных
Когда я работаю над проектами с открытым исходным кодом на C/C ++, именно глобальные переменные не дают мне жить. Вам трудно проводить отладку проекта и задавать параметры многопоточности, потому что вы устроили настоящий рассадник глобальных переменных. Минимизируйте их использование – и рефакторинг кода станет куда эффективнее.
Да, если мы говорим о системе отладки/ регистрации статуса, обращаться к глобальным переменным даже нужно, а в остальных случаях – просто забудьте об их существовании.
Немного ООП, добавим функциональное программирование и чуть-чуть Java
Нередко шутят, что «я могу программировать на FORTRAN на любом ЯП», ссылаясь на то, что программисты часто используют тот или иной язык не по назначению, пытаясь свести его к знакомым инструментам. Но это как сказать, что немые программисты остаются немыми, с каким бы языком программирования не столкнулись. Хотя иногда универсальные свойства, присущие различным системам программирования тоже отлично работают.
В объектно-ориентированном программировании нас интересует то, как концепция структуры объединяет данные и методы, которые необходимы для обработки информации. Для struct Fooba вы создаете ряд функций, которые сводятся к foo_xxxx(). К вашим услугам конструктор foo_create(), деструктор foo_destroy() и море функций, определяющих структуру.
Самое главное: описывать struct Foobar в файле C, а не в файле заголовка. Пусть функции будут общедоступными, но вот точный формат структуры, желательно, скрыть. Как правило, на структуры даются прямые ссылки, что особенно важно для библиотек, экспорт заголовков которых сказывается на совместимости бинарных интерфейсов приложений (так как меняется размер структуры). Если необходимо экспортировать структуру, в качестве первого параметра указывайте версию или размер.
Нет, я не собираюсь вдаваться в подробности ООП вплоть до наследования и полиморфизма. Наоборот, хотелось просто отметить, что можно взять на заметку преимущества модульного программирования, которые, в принципе, схожи с ООП.
Кроме того, никто не отменял несколько хороших идей и в функциональном программировании, а именно те из присущих ему функций, которые не имеют «побочных эффектов». Это опции, рассчитанные на то, что есть исходные данные и определенная информация на выходе. Никакой самодеятельности. Большинство написанных вами функций должны выглядеть именно так. Если же вы сочиняете что-то вроде void foobar(void); — ждите неприятностей.
В списке инструментов, заметно усложняющих жизнь, упоминаются и глобальные переменные. В эту же категорию попадают и вызовы системы, снижающие ее производительность. Глобальные переменные, по сути, похожи на переменные, скрытые глубоко в теле структуры, которые вы вызываете через int foobar(struct Xyz *p);. В результате приходится копаться в недрах р, чтобы найти необходимые параметры. Проще, когда все это лежит на поверхности, тогда запрос формируется по типу foobar(p->length, p->socket->status, p->bbb). Да, в этом случае приходится работать с длинными, раздражающими списками параметров, но так вместо сложной структуры функция foobar() зависит от простых типов.
Отчасти подобный функциональный подход к программированию обусловлен использованием констант, где указатели задаются через const, а, значит, функция не может их изменить. Зато ясно, где результаты (возвращаемое значение и неконстантные указатели), а где исходные данные.
С – язык программирования систем низкого уровня, но, если не считать явно сложных случаев, постарайтесь им не злоупотреблять. Вместо конкретных приемов С используйте инструменты, с помощью которых ваш код будет жизнеспособным в более широкой среде, пусть даже и похожей на условия С. Так вы сможете интегрировать его с JavaScript, Java, C # и др.
Придется обойтись без арифметики указателей. Да, в 1980-х она позволила существенно ускорить код, но с 1990-х от нее больше никакой пользы, особенно, в случае с современными оптимизирующими компиляторами. Арифметика указателей только снижает читабельность кода. Почти всякий раз, когда проект с открытым исходным кодом подвергается воздействию кибермошенников (Hearbleed (по всей видимости, имелось ввиду Heartbleed прим.), Shellshock, и т.д.), ищите причину в коде с арифметикой указателей. В качестве альтернативы обратите внимание на переменные целочисленных индексов и проанализируйте соответствующие массивы данных, как если бы вы писали это на Java.
Такой идеальный подход к написанию кода подразумевает и отказ от парсинга сетевых протоколов/форматов файлов для структур/целых. Да, пособие по сетевому протоколированию советует использовать что-то вроде noths(*(short*)p), только вот совет этот уже во время написания книги был не самым удачным, а сегодня и вовсе неуместен. Анализируйте целочисленные параметры, как на Java: p[0] * 256 + p[1]. Вам кажется, что закрепив упакованную структуру на поверхности, ее проще будет анализировать – не тут-то было.
Блокируйте небезопасные функции
Хватит использовать устаревшие функции из разряда strcpy() и sprintf(). Если я нахожу уязвимости, скорее всего, они именно здесь. Более того, с таким набором аудит вашего кода стоит гораздо дороже, ведь нужно просмотреть каждую из вышеупомянутых функций, чтобы убедиться, что буфер не переполнен. Возможно, вы уверены, что с буфером все в порядке, но мне придется долго и нудно это проверять. Нет, чтобы писать strlcpy()/strcpy_s(), и snprintf()/sprintf_s().
В целом, вы действительно должны отдавать себе отчет в том, что такое переполнение буфера и переполнение размеров переменной. Посмотрите, как на OpenBSD используется reallocarray(), разберитесь, почему данная опция позволяет решить проблему переполнения размеров переменной, а затем постарайтесь использовать ее во всех своих кодах вместо malloc(). Если придется, скопируйте исходный reallocarray() из OpenBSD и придерживайтесь этой функции в ваших программах.
Вы знаете, почему код вдруг дают сбой при вводе определенных данных? Может, дело в их безопасности. И, кстати, почему ваш код взламывают злоумышленники? Будете все делать правильно – больше о подобных проблемах беспокоиться не придется.
В статье «Программирование на С в 2016 году» прозвучал совет везде использовать calloc(). Не спешите ему следовать, ведь в этом случае на многих платформах вы все равно столкнетесь с переполнением размеров переменной. Кроме того, привыкайте к функциям вроде realloc(), а заодно и reallocarray().
Существует множество правил написания безопасного кода, но если вы выполните то, что я сказал, решите большинство проблем в этой сфере. И, да, скептически воспринимайте любые исходные данные, даже если речь идет о локальном файле или USB-порте, который, казалось бы, под контролем.
Долой странный код
Чего не хватает всем компаниям, специализирующимся на разработке программного обеспечения, так это собраний после работы, на которые может прийти любой желающий и озвучить предложения по единому стилю создаваемых кодов. Затем просто увольняем всех, кто выпендривается. Звучит глупо.
Единственное, что можно назвать правильным «стилем» — сходство кода с его соратниками из Интернета. Это относится и к личным кодам, и к проектам с открытым исходным кодом, над которыми вы обычно работаете. Вам нужно всего лишь выбрать один из существующих известных стилей, вроде предлагаемых Linux, BSD, WebKit, или Gnu.
Среди преимуществ других языков программирования, особенно Python, можно отметить весьма небольшое количество общепринятых стилей, чего не скажешь о С. Так, например, при анализе уязвимости Hearbleed выяснилось, что OpenSSL использует скобки Whitesmiths – стиля, который в свое время был общепринятым, но сейчас встречается редко и выглядит странно. LibreSSL преобразовала его в формат BSD. Весьма неплохое решение: если ваш стиль на С слишком витиеват/устарел, возможно, пора сменить его на что-то распространенное/привычное.
Вы уверены, что все станут использовать те же крутые штуки, что и вы, как только увидят, как клево они смотрятся в вашем коде? Нет уж, избавьтесь от них, они только раздражают людей. Или, если такие инструменты жизненно необходимы (бывает и такое), задокументируйте свой опыт.
Будущее за многоядерными процессорами
Процессоры вряд ли станут быстрее. Как видите, просто появляется все больше и больше ядер. Нет, это не значит, что вам не нужно писать многопотоковый код, но, вероятно, стоит задуматься и об их будущем.
Скажите нет мьютексам и критическим секциям – они только усложняют ваш код. Да, это повышает безопасность продукта, но ведь страдает производительность. Так ваш код может летать на 2 или 3 ядрах, но если их больше, программа начинает тормозить. Важнее масштабируемости под разное количество ядер в рамках программирования на языке С может быть только обеспечение достойного уровня безопасности продукта.
Думаю, очень скоро вы познакомитесь с огромной статьей, посвященной масштабируемости под различные системы, а пока просто делайте, как я уже говорил: избавьтесь от глобальных переменных и скрытых функций обмена данными встроенных структур. Потом, когда нужно будет заняться рефакторингом кода и его масштабом, работать будет в разы проще.
Забудьте о true/false для success/failure
В статье «Программирование на С в 2016 году» сказано, что success всегда равняется true. Чушь. True это true, а success это success. Не ставьте между ними знак равенства. Чтобы получить 0 в случае успешного результата и другое значение при отказе функции, придется написать сложнейший код.
Да, вот такая ерунда: стандарта нет, и вряд ли когда-либо появится. Вместо того, чтобы прислушиваться к вредному совету из «Программирования на С в 2016 году», посмотрите, как doc прекрасно справляется с задачей «долой странный код». Автор считает, что если бы мы научили других делать так же, если бы не запутывали собственный код, подавая тем самым хороший пример, тогда от проблемы не осталось бы и следа. Наивно. Программисты никогда не согласятся с этим стандартом. Вашему коду придется выживать в мире, полном неоднозначности, где и true, и 0 означают success, несмотря на изначально противоположные значения. Создание стандарта возможно только при однозначном определении показателей SUCCESS и FAILURE.
Если код выглядит так:
Немного о целых величинах
Автор статьи «Программирование на С в 2016 году» утверждает, что нет никаких оснований использовать классические int или unsigned, а вместо них лучше обращаться к int32_t и uint32_t. Нонсенс! Команды int и long являются общепризнанными для ввода исходных данных в большинстве функций библиотек, причем именно они обеспечивают своего рода защиту типов и уведомляют пользователей даже при запросе различных типов одного размера.
Честно говоря, задать неверные значения целых несложно, в том числе и на 64 и 32-битных системах. Да, использование int для управления указателем сломает 64-битный код (вместо этого пишите intptr_t, ptrdiff_t или size_t), но, вы не поверите, как редко это случается на практике. Просто задайте mmap() для 4 первых гигабайт, пометив, что при загрузке эти страницы недействительны, проведите модульное/регрессионное тестирование — и вы быстро решите любую проблему. Причем мне вовсе не нужно вам объяснять, как это лучше сделать.
Что раздражает в коде больше всего, так это то, что программисты вечно спешат повторно определить типы целых величин. Завязывайте. Я понимаю, что u32 придает особый шарм коду, но меня этот элемент просто выводит из себя. А ведь именно мне придется читать код. Пожалуйста, замените его на что-нибудь стандартное, например, uint32_t или unsigned int. И, о ужас, хватит произвольно создавать типы целых вроде filesize. Я знаю, что вы хотите придать выбранному целому новый смысл, но не забывайте, что программирование на C рассчитано на «низкий уровень», а потому программисты просто умирают в процессе проверки таких перлов.
Используйте статический и динамический анализ
Если раньше специфика C сводилась к «уровням предупреждений» и опции «линт», на сегодняшний момент их место занял «статический анализ». С помощью Clang компиляторы радуют пользователей все новыми и новыми сообщениями, да и gcc старается на отставать. И, хотя многие не в курсе, компиляторы Microsoft также предлагают статический анализ на уровне Clang. Возможности XCode в сфере визуализации анализа Clang действительно впечатляют, хотя речь идет о тех же механизмах, что и в самом Clang.
Но это только общий статический анализ. А ведь есть еще много инструментов для обеспечения безопасности, которые поднимают статический анализ на более высокий уровень — Coverity, Veracode и HP Fortify.
Тут не обходится без принципа «ошибочного допуска», а ведь это неправильное определение. Прописывая в коде такие команды, вы его «подчищаете», а, значит, получаете куда более надежные результаты. Другими словами, попдная схема позволяет довести код до совершенства, удаляя ненужные элементы. Написание кода под четким надзором статического анализатора совершенствует навыки программирования.
Эти ужасные зависимости
После нескольких лет существования корпораций проекты появляются только на текущей системе. А все потому что накапливается огромное множество несистематизированных зависимостей. В одной из компаний, где я работал шутили, что им придется поделиться материалами с конкурентами, так как иначе они ни за что не вспомнят, как осилили те или иные разработки.
И по весьма веским причинам такая практика закрепляется навсегда. В другой компании предложили унифицировать версии компиляторов во избежание проблем с интеграцией, возникающих при использовании командами сотрудников разных компиляторов. Но такой подход решает относительно незначительную проблему, на смену которой приходит куда более серьезная. Устраняя вопросы с интеграцией, вы проводите своеобразную санацию кода.
Открытый исходный код тоже подразумевает определенные сложности. Зависимости редко документируют полностью, а вот недочетов в них – хоть отбавляй. В большинстве подобных случаев, в итоге, вы тратите море времени на установку двух несовместимых версий одной зависимости, чтобы, о чудо, скомпилировать необходимый код.
Чем меньше зависимостей, тем популярнее становится код. Для этого вам нужно всего лишь:
- Удалить зависимости. Как правило, лишь 1% зависимостей приносит программисту пользу, остальные 99% — затрудняют работу.
- Использовать только необходимый исходный файл. Вместо того, чтобы завязать все процессы на целой библиотеке OpenSSL (и ее зависимостях), просто добавьте файл sha2.c, если, конечно, вам не понадобятся другие функции OpenSSL.
- Пусть источник всех зависимостей будет прямо в дереве. Например, Lua – шикарный скриптовый язык в 25kloc, которому просто необходимы обновления. Вместо того, чтобы бросать пользователей на произвол судьбы в погоне за соответствующей зависимостью lua-dev, укажите источник Lua в своем дереве.
- Загружайте библиотеки в процессе запуска программы через dlopen(), не забывая про файлы их интерфейсов .h, которые также являются частью источника вашего проекта. Это значит, что у вас не будет проблем с той или иной зависимостью, пока она не нужна для функционирования библиотек. Или, если без нее никак, можете подготовить уведомления об ошибках с предусмотренными инструкциями по исправлению неполадок зависимости.
Разберитесь с неопределенными поведением на C
Скорее всего, вы не совсем понимаете, как работает язык C. Рассмотрим выражение (х + 1 < х). Действительный результат в этом случае 5. А все потому, что С не задает действия для x, если данная переменная получает максимальное целое значение и вы прибавляете 1, что приводит к ее переполнению. Многие компиляторы идентифицируют подобные явления, как переполнение в двоичном коде, так же, как и другие языки программирования (например, Java). Но, как известно, некоторые компиляторы автоматически классифицируют такого рода ситуации, как невозможные, и просто удаляют весь соответствующий код.
Таким образом, вам придется исходить не из того, как работает текущая версия вашего компилятора на С, а вникнуть в дополнительные аспекты, проанализировав, как на код могут отреагировать другие компиляторы на С.
Как пишется слово: «со» или «с»

Стоит знать, что предлог с(со) является служебной частью речи. А могут ли возникнуть вопросы при написании слова? Я думаю, что да. Поэтому, давайте разберёмся.
Как же правильно пишется: «со» или «с»?
Согласно орфографической норме русского языка изучаемое слово пишется, как в первом варианте, так и во втором:
В каких случаях следует написать предлог «со»?
Для того, чтобы понять какой предлог нужно написать, следует обратить внимание на слово, к которому этот предлог относится.
Следует написать предлог «со», если:
- следующее слово начинается с двух или более согласных, первая из которых «с» или «з».Например: со страху, со слезами, со зла, со слов, со звездой
- если слово начинается с любых двух и более согласных, а также если есть «л», «р», «н», «с». Например: со льдом, со многими, со шторами, со мною
- если слово начинается со звуком «щ».Например: со щукой, со щами, со щенком
- в отдельных фразеологических выражениях.Например: со белой руки, нет меду со пчёл
В каких случаях напишем предлог «с»?
А во всех остальных случаях следует употреблять предлог «с»!
Таким образом, следует запомнить правила выше, а также стараться не допускать ошибок!
Чтобы или что бы?
Наверное, одной из самых частых ошибок при письме в русском языке становится написание слов ЧТО БЫ и ЧТОБЫ: многие авторы пишут слитно там, где нужно раздельно, и наоборот. Есть и те, кто в любом случае использует только один вариант, даже не догадываясь, что писать нужно по-разному. Так как же именно – слитно или раздельно? Разбираемся.

Правописание слова
Сразу отметим, что раздельное написание встречается куда реже слитного, однако путать их не следует. Подчинительный союз ЧТОБЫ пишется без пробела; местоимение ЧТО и сослагательная частица БЫ пишутся через пробел. Но трудность обычно и состоит как раз в определении части речи. Как же понять, где союз, а где местоимение и частица?
Слитное написание слова чтобы
Легче всего запомнить, что слитное написание ЧТОБЫ, то есть союза, используется в случае постановки какой-то цели, то есть «для чего-то». Такой союз используется в сложноподчиненном предложении и, как правило, его можно дополнить словами «для того». Сравните: «ЧТОБЫ приготовить курицу / для того чтобы приготовить курицу». Как видим, смысл фразы не меняется.
Ну и еще для облегчения запоминания, что этот союз пишется вместе, можно попытаться удалить частицу. Если фраза становится бессмысленной – «что приготовить курицу» – значит, пишем слитно.
Существует еще составной союз ДЛЯ ТОГО ЧТОБЫ. Смысл он имеет тот же, что и просто союз, но при этом легко запоминается правописание: если есть ДЛЯ ТОГО, то ЧТОБЫ будет писаться только слитно.
Пунктуация
Учитывая, что союз ЧТОБЫ используется в сложноподчиненном предложении, где-то рядом непременно должна быть запятая! Если зависимая часть предложения стоит первой, то запятая будет отделять главную часть. Если же придаточная часть – вторая, то запятая ставится непосредственно перед ЧТОБЫ:
- ЧТОБЫ надеть платье, мне пришлось перешивать пуговицы.
- Я перешила пуговицы, ЧТОБЫ надеть платье.
Составной союз ДЛЯ ТОГО ЧТОБЫ, как правило, не разделяется запятыми. Пунктуация здесь та же, что и для обычного союза ЧТОБЫ:
- Для того чтобы надеть платье, мне пришлось перешивать пуговицы.
- Я перешила пуговицы, для того чтобы надеть платье.
Однако в некоторых случаях союз может разделяться запятой: ДЛЯ ТОГО, ЧТОБЫ. Обычно это происходит для интонационного акцентирования в придаточной части цели действия, указанного в главной части предложения:
- Я перешила пуговицы только для того, чтобы надеть платье!
Примеры предложений
- Сегодня пришлось одеться теплее, чтобы не замерзнуть.
- Чтобы одеть младенца, наберитесь терпения и выпейте валерьянки.
- Светка размахивала новой сумочкой как раз для того, чтобы похвастаться.
- — Желаю тебе, чтобы в твоей жизни все всегда шло гладко и все получалось, — сказал Сергей.
- Отец заставлял Сашку хорошо учиться, чтобы «выйти в люди».
Раздельное написание слов что бы
ЧТО БЫ пишется раздельно в случае если это местоимение и сослагательная частица. При этом частицу можно безболезненно удалить из фразы, и смысл ее останется почти прежним. Можно также попробовать заменить местоимение фразой «то или это». Проверяем:
- Что бы ты купил на миллион рублей? – Что ты купишь на миллион рублей?
- Что бы нам заказать на обед? – Нам на обед заказать то или это?
- Что бы я ни съел, мне не понравится. – Что я съем – мне не понравится.
- Что бы купить, чтоб не разориться? – Что купить, чтоб не разориться?
И нужно запомнить следующее: устойчивое выражение «во что бы то ни стало» пишется всегда раздельно и без запятых.
Примеры предложений
- Что бы ты посоветовал мне почитать на ночь?
- — Что бы это могло значить? – задумался Пашка.
- Что бы ты тут ни съел – не отравишься, — успокоил дед.
- Что бы я ни посадил – вырастает капуста, — смеялся дядька.
Ошибочное написание
Некоторые люди пишут союз через дефис – что-бы. Это неверно и не будет верным ни в каком случае.
Ошибкой будет также перепутать слитное и раздельное написание.
Заключение
Особых сложностей, как видим, в правописании нет: чтобы запомнить, как пишется ЧТОБЫ и ЧТО БЫ, достаточно запомнить некоторые моменты и научиться изменять форму предложения, чтобы проверить, изменился ли его смысл.
А если вы хотите проверить, насколько точно вы усвоили употребление этих слов, мы предлагаем пройти вам небольшой тест.