Степень универсальности по сравнению с безопасностью типов? Используя пустоту* в C

Происходя из OO (C#, Java, Scala) я оцениваю очень высоко принципы и повторного использования кода и безопасности типов. Аргументы типа на вышеупомянутых языках делают задание и включают универсальные структуры данных, которые и безопасны с точки зрения типов и не 'тратят впустую' код.

Поскольку я застреваю в C, я знаю, что должен пойти на компромисс, и я хотел бы, чтобы он был правильным. Любой мои структуры данных имеют a void * в каждом узле / элемент и я теряем безопасность типов, или я должен переписать свои структуры и код для каждого типа, с которым я хочу использовать их.

Сложность кода является очевидным фактором: итерация через массив или связанный список является тривиальным и добавляющим a *next к структуре не дополнительное усилие; в этих случаях имеет смысл не пытаться снова использовать структуры и код. Но для более сложных структур ответ не так очевиден.

Существует также модульный принцип и тестируемость: выделение типа и его операций от кода, который использует структуру, делает тестирование ее легче. Инверсия также верна: тестирование повторения некоторого кода по структуре, пока это пытается сделать другие вещи, становится грязным.

Таким образом, каков Ваш совет? void * и повторное использование или безопасность типов и дублированный код? Есть ли какие-либо общие принципы? Я пытаюсь вызвать OO на процедурный, когда оно не будет соответствовать?

Править: Не рекомендуйте C++, мой вопрос о C!

16
задан Joe 14 December 2009 в 09:43
поделиться

10 ответов

I would say use void * so you can re-use the code. It's more work to re-implement e.g. a linked list, than to make sure you get/set the data in the list properly.

Take as many hints from glib as possible, I find their data structures very nice and easy to use, and have had little trouble because of the loss of type safety.

13
ответ дан 30 November 2019 в 17:39
поделиться

I think you'll have to strike a balance between the two, just as you suggest. If the code is only a few lines and trivial I would duplicate it but if it's more complex, I would consider working with void* to avoid having to do any potential bug fixing and maintenance in several places and also to reduce the code size.

If you look at the C runtime library, there's several "generic" functions that work with void*, one common example is sorting with qsort. It would be madness to duplicate this code for every type you'd like to sort.

6
ответ дан 30 November 2019 в 17:39
поделиться

Нет ничего плохого в использовании указателей void. Вам даже не нужно приводить их при присвоении переменной типа указателя, поскольку преобразование выполняется внутри. Стоит взглянуть на это: http://www.cpax.org.uk/prg/writings/casting.php

4
ответ дан 30 November 2019 в 17:39
поделиться

You can build a (sort of) OO framework using C, but you miss out on a lot of the benefits ... like an OO type system that the compiler understands. If you insist on doing OO in a C-like language, C++ is a better choice. It is more complicated than vanilla C, but at least you get proper linguistic support for OO.

EDIT: Ok ... if you insist that we don't recommend C++, I recommend that you don't do OO in C. Happy? As far as your OO habits are concerned, you should probably think in terms of "objects", but leave inheritance and polymorphism out of your implementation strategy. Genericity (using function pointers) should be used sparingly.

EDIT 2: Actually, I think that use of void * in a generic C list is reasonable. It is just trying to build an mock OO framework using macros, function pointers, dispatching and that kind of nonsense that I think is a bad idea.

0
ответ дан 30 November 2019 в 17:39
поделиться

Вы можете использовать макросы, они будут работать с любым типом, и компилятор будет статически проверять расширенный код. Обратной стороной является то, что плотность кода (в двоичном файле) ухудшится, и их будет труднее отлаживать.

Я задал этот вопрос об общих функциях некоторое время назад, и ответы могут вам помочь.

1
ответ дан 30 November 2019 в 17:39
поделиться

Вы можете эффективно добавлять информацию о типе, наследовании и полиморфизме в структуры данных C, это то, что делает C ++. ( http://www.embedded.com/97/fe29712.htm )

1
ответ дан 30 November 2019 в 17:39
поделиться

См. Также Может ли существовать огромный приложение будет перенесено в сеть? но он может получить доступ к простой функции C с помощью Pinvoke, поэтому, что бы вы ни делали, на сайте C ++ потребуется какой-то связующий слой.

  • Посмотрите, можете ли вы использовать Silverlight, а не Интернет, если вы можете (проблемы с установкой и т. ) это сэкономит вам много времени на разработку. (И также позволяет настраивать таргетинг на телефоны Microsoft.)
  • Убедитесь, что экономическое обоснование «порта в Интернет» очень сильное, и это займет намного больше времени, чем вы думаете! , Хостинг с сервер терминалов и т. д. вариант для ваших клиентов ?
  • Подумайте о многопоточности и многопользовательском доступе, например, ваша dll предполагает, что она используется только одним пользователем?
  • Просто потому, что вы работаете над новая веб-версия, вы по-прежнему будете получать клиентов, требующих изменений в настольной версии, даже после того, как вы отправите веб-версию.
  • 3
    ответ дан 30 November 2019 в 17:39
    поделиться

    Мой текущий магазин имеет большую базу кода, которая запускает финансовые приложения со сложными бизнес-правилами. Некоторые из этих правил закодированы в хранимых процедурах, некоторые - в триггерах, а некоторые - в коде приложений 3gl и 4gl. Есть работающий код конца 90-х, и его нет на ваших «традиционных» устаревших языках, таких как COBOL или FORTRAN. Как можно догадаться, это дымящаяся куча спагетти-кода, большая часть из которых была создана до того, как TDD что-то значило, поэтому люди не хотят ничего трогать.

    Если вы проверите подписи malloc / realloc , вы увидите, что вы можете добиться правильного распределения памяти без ужасного указателя void ** . Я говорю это только потому, что видел это в каком-то проекте с открытым исходным кодом, который я не хочу здесь называть.

    0
    ответ дан 30 November 2019 в 17:39
    поделиться

    Определенно общий void * , никогда не дублируйте код!

    Примите во внимание, что эту дилемму рассматривали многие программисты на C и многие крупные проекты C. Все серьезные проекты C, с которыми я когда-либо сталкивался, будь то с открытым исходным кодом или коммерческие, выбирали общий void * . При осторожном использовании и в комплекте с хорошим API это практически не обременяет пользователя библиотеки. Более того, void * является идиоматическим C, рекомендованным непосредственно в K и R2. Именно так люди ожидают написания кода, а все остальное было бы неожиданно и плохо принято.

    1
    ответ дан 30 November 2019 в 17:39
    поделиться

    Здесь мы часто используем объектно-ориентированный язык в C, но только для инкапсуляции и абстракции, без полиморфизма или около того.

    Это означает, что у нас есть определенные типы, такие как FooBar (Foo a, ...), но для нашей коллекции "классы" ", мы используем void *. Просто используйте void * там, где можно использовать несколько типов, НО, делая это, убедитесь, что вам не нужен аргумент определенного типа. Что касается коллекции, иметь void * - это нормально, потому что коллекция не заботится о типе. Но если ваша функция может принимать тип a и тип b, но никого другого, создайте два варианта, один для a и один для b.

    Главное - использовать void * только тогда, когда вам не важен тип.

    Теперь,

    2
    ответ дан 30 November 2019 в 17:39
    поделиться
    Другие вопросы по тегам:

    Похожие вопросы: