Показаны сообщения с ярлыком c. Показать все сообщения
Показаны сообщения с ярлыком c. Показать все сообщения

2015-03-05

Из анонса новой CRT в Visual Studio

...
The "best" example of this maintainability problem could be found in the old implementation of the printf family of functions. The CRT provides 142 different variations of printf, but most of the behavior is the same for all of the functions, so there are a set of common implementation functions that do the bulk of the work. These common implementation functions were all defined in output.c in the CRT sources(1). This 2,696 line file had 223 conditionally compiled regions of code (#ifdef, #else, etc.), over half of which were in a single 1,400 line function. This file was compiled 12 different ways to generate all of the common implementation functions. 
...
We have converted most of the CRT sources to compile as C++, enabling us to replace many ugly C idioms with simpler and more advanced C++ constructs. The publicly callable functions are still declared as C functions, of course (extern "C" in C++), so they can still be called from C. But internally we now take full advantage of the C++ language and its many useful features.
...
Before this refactoring, the sprintf functions, which write formatted data to a character buffer, were implemented by wrapping the result buffer in a temporary FILE object and then deferring to the equivalent fprintf function. 

2013-05-08

Много видал я извращений с макросами, но такого ...

Cello is a GNU99 C library which brings higher level programming to C.

Interfaces allow for structured design;
Duck Typing allows for generic functions;
Exceptions control error handling;
Constructors/Destructors aid memory management;

Ссылки на примеры:
Пример программы:

#include "Cello.h"

int main(int argc, char** argv) {

  /* Tables require "Eq" and "Hash" on key type */
  var prices = new(Table, String, Int);
  put(prices, $(String, "Apple"),  $(Int, 12)); 
  put(prices, $(String, "Banana"), $(Int,  6)); 
  put(prices, $(String, "Pear"),   $(Int, 55));

  /* Tables also supports iteration */
  foreach (key in prices) {
    var price = get(prices, key);
    print("Price of %$ is %$\n", key, price);
  }

  /* "with" automatically closes file at end of scope. */
  with (file in open($(File, NULL), "prices.bin", "wb"))) {

    /* First class function object */
    lambda(write_pair, args) {

      /* Run time type-checking with "cast" */
      var key = cast(at(args, 0), String);
      var val = cast(get(prices, key), Int);

      try {
        print_to(file, 0, "%$ :: %$\n", key, val);
      } catch (e in IOError) {
        println("Could not write to file - got %$", e)
      }

      return None;
    };

    /* Higher order functions */
    map(prices, write_pair);
  }

  delete(prices);
}

На что только люди не пойдут, чтоб на С++ не писать.

2013-02-25

программистской мизантропии псто

Почти 5 лет (c 2006 по 2011) я, в основном, занимался одним проектом. Можно сказать, "варился в собственном коде". Да, там есть "странные" вещи, вроде самопального rtti с регистрацией в фабрике, но в целом, смею надеяться, код пристойного качества.
С начала 2011 года поучаствовал в полудюжине проектов, как доставшихся "в наследство", так и новых, как целиком проприетарных, так и использующих opensource библиотеки. И что-то с каждым таким проектом мне все грустнее...

Пытаюсь понять, что движет:
  • людьми, разрабатывающими пакетный менеджер под embedded-систему, который не проверяет, достаточно ли свободного места для установки пакета.  И который, когда место заканчивается, оставляет систему в невалидном состоянии:
    • Raspbian: попытка освободить место через `apt-get remove что-нибудь` требует `dpkg --configure -i`, который пытается уставить те самые пакеты, которым не хватило места.  Хорошо, что пишка грузится с карточки, которую проще залить заново с образа, чем разбираться с глюками.
    • Angstrom: opkg ведет себя еще веселее, игнорируя ошибки установки пакетов, а потом, поскольку один из пакетов был "системным", перезагружая устройство. Которое у меня больше не завелось.
  • человеком, пишущим библиотеку, в которой все контейнеры хранят void*,  вместо enum везде используется int, но поля to, from, cc, bcc в заголовке e-mail имеют разный тип:
    struct env_to { list * to_list; };
    struct env_from { list * from_list; };
    struct env_cc { list * cc_list; };
    typesafety, чо.
    Ну, и предлагающим использовать функции вроде
    imap_search_key_new(IMAP_SEARCH_KEY_UNSEEN, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL)
  • людьми, радикально меняющими апи в минорном апдейте.
  • мейнтейнерами/авторами библиотеки, последняя версия которой в дистрибутивах Linux (и в Mac OS X) содержит ошибку, не позволяющую работать с буфером больше 64 кБ. Ошибке уже больше года, и не смотря на то, что она давно исправлена в master, в недавно вышедший апдейт ее фикс не вошел.
  • давно уже  не джуниором, который пишет на языке, где все функции виртуальны, код:
    void Shape::draw() {
      switch (this.kind) {
      case KindRect: ((RectShape)this).draw(); break;
      case KindCircle: ((CircleShape)this).draw(); break;
    ...
  • людьми, которые поучаствовали в десятке проектов, были lead developer-ами на двух-трех из них, но при этом стабильно плодящими копи-пасту в своем коде. 
  • людьми, которые думают, что пишут на С++, потому что используют слово class вместо struct и new/delete вместо malloc/free.
  • человеком, который после, ЕМНИП, 2-х лет работы подошел ко мне, и спросил: "как пользоваться svn"
  • людьми, заводящими массив констант на 3,5 KLOC. Который нужно обновлять вручную пару раз в месяц.
  • людьми, чьи классы так плотно завязаны друг на друга и платформенно-зависимый код, что попытка собрать часть проекта на другой, пусть и родственной платформе обречена на провал.
Нет, я, конечно, тоже не д'Артаньян. Бывает, допускаю memleak или double free в С или Objective-C. Бывает, коммичу в транк нерабочий код. У всех бывают факапы.
Но, блеать, некоторые их замечают и фиксят.

2013-01-24

сишники узнали о for_each

Из одной библиотеки (на которую я уже жаловался)

typedef void (* clist_func)(void *, void *);
void clist_foreach(clist * lst, clist_func func, void * data) {
  clistiter * cur;
  for(cur = clist_begin(lst) ; cur != NULL ; cur = cur->next)
    func(cur->data, data);
}

//....

clist_foreach(list, (clist_func)free, NULL);

Если кто забыл -- void free(void*). То есть, имеем UB по стандарту С. Да, оно работает, пока cdecl и компилятор не намудрит с оптимизацией.

Интересный факт: так как это UB, компилятор имеет право делать все, что угодно. Prerelease GCC 4.3, если типы функций были несовместимы, возвращал NULL. К релизу пришлось поменять назад, ибо дофига софта "поломалось".

2012-12-04

OpenSource такой OpenSource

Ломать бинарную совместимость при смене версии с 0.8 на 0.9? Сжав зубы, такое можно "понять и простить".

Но ломать совместимость между libxxx-dev_1.0.1-1 и libxxx-dev_1.0.1-1.1, поменяв названия типов и не оставив define или typedef для старых имен?

И да, о #include <stdint.h> мы тоже не слышали:
typedef unsigned int uint32;

2012-12-03

когда коту делать нечего...

Emscripten is an LLVM to JavaScript compiler. It takes LLVM bitcode (which can be generated from C/C++ using Clang, or any other language that can be converted into LLVM bitcode) and compiles that into JavaScript, which can be run on the web (or anywhere else JavaScript can run).
Using Emscripten, you can
  • Compile C and C++ code into JavaScript and run that on the web
  • Run code in languages like Python as well, by compiling CPython from C to JavaScript and interpreting code in that on the web
.....

      • This is the Lua interpreter, compiled from C to JavaScript using Emscripten, running in your browser (without any plugins).
      • TrueType font rendering in JavaScript, using FreeType
      • lzma.js - LZMA ported to JS
      • sql.js - SQLite ported to JS

      Куда катится мир .. (с) nponeccop

      2012-11-26

      When ...

      When I see three layers of weird DSLs for configuring a single app

      When somebody says “it’s written in C, so it must be fast”

      When somebody tries to explain JavaScript’s prototype system

      When I hear your new PL doesn’t have exceptions and requires manual error handling instead

      When somebody says he doesn’t like exceptions because he likes to handle errors where they appear

      Moar here

      2012-08-23

      Кавычки нам не нравятся

      gcc-llvm в макос игнорирует параметры -isysroot и -idirafter, если их параметр указать в кавычках.
      g++ -idirafter /opt/local/include
      работает, а
      g++ -idirafter "/opt/local/include"
      нет.
      И кто они после этого. 

      2012-01-10

      "Pure C" Ненависти Псто.

      Пишу обвертку вокруг одной библиотеки, написанной на "сишечке".
      • Пяток структур и полсотни функций в каждом хидере, документирована от силы четверть. Итого -- тысячи функций, которые вроде бы умеют все, но чтобы сделать что-то, на пол-шага отличающееся от примеров, приходится достаточно долго курить, а клиентский код получается весьма обширным. В результате -- за деревьями не видно леса.   
      • Отсутствие модификаторов доступа в С -- мне как клиенту библиотеки непонятно, какие данные я могу менять напрямую, а какие -- через функции библиотеки. Можно было бы спрятать приватные данные в pimpl, но автор до этого не додумался.
      • Pure C реализации вектора/списка/хешмапы. Через void*, по другому ведь никак. Типобезопасность? Нет, не слышали. Хорошо, если комментарий есть -- "в этом списке char*, в этом -- struct foo*. В динамических языках хоть ассерт можно поставить, в С -- либо все ок, либо расстрел памяти.
      • Вау, автор додумался до идеи конструктора/деструктора. Поэтому для каждой струкутры есть
        struct lib_foo * lib_foo_new(/*параметры*/); 
        void lib_foo_free(struct lib_foo*);
        
        даже если это
        struct lib_foobar {
          int fb_foo;
          int fb_bar;
        };
        
        Соответственно, все обьекты выделяются через malloc в хипе, в том числе и члены членов членов членов главной структуры. 
      • А до виртуального деструктора автор не додумался (Или решил, что это оверхед). Поэтому при оборачивании обьекта в умный указатель приходится постоянно передавать ему делитер.
      • Привычка добавлять сокращенное имя структуры как префикс поля (те самые fb_) в примере выше. В результате -- в клиентском коде будет куча копи-пасты вида
        lib_foo_list * fill_foo(...) {
          lib_foo_list * foos = lib_foo_list_new();
          fill(foos->foo_list, ...)
          return foos;
        }
        
        lib_bar_list * fill_bar(...) {
          libbar_list * bars = lib_bar_list_new();
          fill(bars->bar_list, ...)
          return bars;
        }
        
        lib_baz_list * fill_baz(...) {
          libbaz_list * bazs = lib_baz_list_new();
          fill(bazs->baz_list, ...);
          return bazs;
        }
        
        которую не засунуть в шаблон.
      • Попытка сэкономить на копировании приводит к странному контракту функций - если функция завершилась успешно -- она владеет переданными обьектами. Если с ошибкой - то обьектами владеет клиентский код. Отсюда: 
        1. В клиенской функции нужна секция обработки ошибок. 
        2. Это не типичная для "сишечки"
          clear_foo:
            lib_foo_free(foo);
          clear_bar:
            lib_bar_free(bar);
            
          return err; 
          
          а нечто позапутанней с дополнительными return-ами или goto-ми
      • Еще запутанней с функциями, принимающими char*. Одна функция копирует переданную строку, соседняя -- ее "овладевает". Комментариев обычно нет, смотри примеры или исходный код. И да, строки мы копируем через strdup, а длину меряем через strlen.