Существует ли гибрид C и C#?

Рейтинг: -3Ответов: 2Опубликовано: 19.09.2014

После C# переход на C слегонца фрустрирует. Дело не в сборке мусора, LINQ и метапрограммировании с компонентной моделью, которое я люблю использовать при программировании на C#. Понятно, что этого в C быть и не должно, не для тех целей язык. Дело в том, что в C# решены некоторые проблемы, которые можно было бы решить и в C, не меняя его идеологии. Может, существует такой компромиссный язык?

Что мне не нравится в C:

  1. C разрешает обращаться к неинициализированным переменным.
  2. В C не отследить арифметическое переполнение (правда, можно для этого сделать ассемблерную вставку, но она срабатывает только тогда, когда переполнение происходит в последней операции перед ассемблерной вставкой).
  3. C разрешает писать функции, которые, хотя и должны возвращать значение, могут его не возвращать.
  4. Не уверен, что это возможно в рамках архитектуры C, но хорошо бы иметь возможность всегда узнать длину массива, а не только когда он создан в стеке в пределах функции.
  5. C разрешает проваливание в операторах switch после того, как по константе выполнились какие-нибудь инструкции.
  6. Неудобный синтаксис для указателей на функцию. Я не представляю себе, как с помощью такого синтаксиса можно описать функцию, которая возвращает указатель на функцию, которая принимает или возвращает указатель на функцию.
  7. При объявлении функций с переменным числом параметров не указывается тип этих параметров. Хотелось бы, чтобы опционально такая возможность была (в C# эта опциональность достигается наличием типа object). Да и сишный способ разбора этих параметров не отличается прозрачностью. Если бы функцию scanf можно было бы объявить как-нибудь так: scanf(const char*, params void*[] p);, то можно было бы проверить на этапе компиляции, что ей переданы именно адреса, а не непонятно что.
  8. Синтаксис объявления переменных и формальных параметров функций в C неудачный, типы перемешаны с переменными (например, int i, j[10], *p;). Полагаю, неудобства в работе с указателями на функцию и переменным числом параметров растут оттуда.
  9. В C имеет место некоторый бардачок с целочисленными типами данных. Мне нравится, что в C# каждый целочисленный тип называется строго одним ключевым словом, и нет чехарды с тем, что такое int: двух- или четырёхбайтное целое.
  10. Ещё меня смущает адресная арифметика. Мне кажется, указатели надо было сделать неизменяемыми: мы получили некоторый адрес путём & или malloc, и дальше менять его всякими инкрементами не можем. Если хотим изменить значение указателя с помощью адресной арифметики, мы должны создать новый указатель.
  11. Очень бесит, что нельзя объявить переменную цикла при объявлении цикла. Правда, в C++ вроде бы уже можно.
  12. При работе с перечислениями значения указываются без префикса типа перечисления, с префиксом было бы нагляднее.
  13. Непонятно, зачем при объявлении перечисления или структуры без typedef при использовании этих типов надо писать struct ADDRESS или enum week_day вместо просто ADDRESS или week_day.
  14. При работе с битовыми полями хорошо бы было более чётко специфицировать порядок выделения бит. Например, с помощью дополнительной конструкции (типа того, что пишем после точки не только количество бит, но и номер, с которого начинаем).
  15. При работе с перечислениями базовый числовой тип не указывается явно, только по используемым значениям перечисления.

Ответы

▲ 2

А вот насчет описания указателей на функции, пожалуй Вы правы. С другой стороны, а в каком языке и как можно корректно описать функцию, которая принимает и возвращает себя?

--

В принципе, работающий вариант в Си можно описать, например, как-то так (только компилятор не сможет делать корректные проверки)

 typedef void * (*func)(void * (*)(), char *);
 ...
 void * foo (func f, char *msg) {
   ...
   return (f && f != foo) ? f(foo, msg) : foo;
 }

Пример, конечно же, практически бессмысленный (демонстрирует, что функция это по сути просто адрес (т.е. void *)).

▲ 1
  1. В С переменная может быть натянута на какой-нибудь регистр. И тогда она уже не будет неинициализированной, хоть и записывать в нее никто в программе не будет
  2. Все прекрасно отслеживается - настроить сопроцессор и он будет вызывать прерывания при переполнении.
  3. Позабытый return ведет к неопределенному поведению.
  4. Желаете странного. Массив, объявленный динамически - просто адрес в памяти. Возлагать на рантайм еще и обязанность помнить, сколько там этой памяти - больно жирное желание, особенно на микроконтроллерах, у которых этой памяти может быть всего 32 байта. Хотите знать размер - напишите свой код, обслуживающий хранение этого размера.
  5. Оператор множественного выбора реализован как куча банальных переходов по меткам case. Естественно, что будет иметь место "проваливание", и зачастую оно очень удобно и позволяет писать более компактно. Просто не следует забывать о break.
  6. Синтаксис для указателей на функции страшен только первые 116 раз. Потом наступает просветление.
  7. Представьте себе, какую прорву кода надо втащить в рантайм для реализации такой хотелки. Хотите переменное число параметров - можете это реализовать при помощи массива указателей на них. Ничего сложного.
  8. Синтаксис страшен, потому как очень подробен. Если выучить несколько правил, вроде того, что модификаторы * действуют строго на то, что справа и не лепить больше одной переменной на строку, уровень понимания становится выше.
  9. Откройте для себя inttypes.h int32_t - вполне конкретное указание типа и размера.
  10. Адресная арифметика - это то, что заставляет программы на C летать с ракетными скоростями и выжимать из камней ровно те гигафлопсы, которыми гордится intel в своих рекламах.
  11. Как насчет C99? Хоть заобъявляйтесь.

И т.д. и т.п. Большинство ругани и хотелок от непонимания простого факта, что C предназначен конкретно для того, чтобы решительно выжать из железа по максимуму, но без фанатичной зубрежки ассемблера и регистров конкретного камня. Но при этом, знать камень все же нужно. C такой, каково наше вычислительное железо, и вы с этим ничего не сделаете. Хотите программировать ненапряжно - возвращайтесь к C# и прочему расслабону.