Подтвердить что ты не робот

Объясните: "C в основном имеет коррумпированную систему типов"

В книге Coders at Work (p355), Гай Стил говорит о С++:

Я думаю, что решение быть обратная совместимость с C является фатальной изъян. Его просто набор трудностей которые невозможно преодолеть. C в корне коррумпирован система. Его достаточно, чтобы помочь вам избегать некоторых трудностей, но не воздухонепроницаемый, и вы не можете рассчитывать на него

Что он подразумевает, описывая систему типов как "поврежденную"?

Можете ли вы продемонстрировать с помощью простого примера в C?

Edit

  • Цитата звучит полемично, но я не пытаюсь быть. Я просто хочу понять, что он имеет в виду.

  • Просьба привести примеры в C не С++. Меня тоже интересует "фундаментальная" часть:)

4b9b3361

Ответ 1

Очевидные примеры в C безопасности не-типа просто исходят из того факта, что вы можете отливать из void * в любой тип без явного исключения.

struct X
{
  int x;
};

struct Y
{
  double y;
};

struct X xx;
xx.x = 1;
void * vv = &xx;
struct Y * yy = vv; /* no need to cast explicitly */
printf( "%f", yy->y );

Конечно, сам printf не является точно типичным.

С++ не является полностью типичным.

struct Base
{
   int b;
};

struct Derived : Base
{
  int d;

  Derived() 
  {
     b = 1;
     d = 3;
  }
};

Derived derivs[50];
Base * bb = &derivs[0];
std::cout << bb[3].b << std::endl;

У него нет проблем с преобразованием Derived * в базу *, но вы сталкиваетесь с проблемами при попытке использовать Base * в качестве массива, поскольку он будет получать арифметику указателя, все неправильно, и пока все значения b равны 1, вы вполне можете получить 3 (по мере того как ints будет идти 1-3-1-3 и т.д.)

Ответ 2

char buffer[42];
FunctionThatDestroysTheStack(buffer);  // By writing 43 chars or more

Ответ 3

В принципе вы можете использовать любой тип данных для любого типа данных

struct SomeStruct {
    void* data;
};

struct SomeStruct object;
*( (int*) &object ) = 10;

и никто вас не поймает.

Ответ 4

Система типа C имеет некоторые проблемы. Такие вещи, как неявное объявление функций и неявное преобразование из void*, могут SILENTLY нарушать безопасность типа.

С++ исправляет почти все эти отверстия. Система типа С++ НЕ обратная совместимость с C, она совместима только с хорошо написанным шрифтом C кода.

Кроме того, люди, выступающие против С++, обычно указывают на Java или С# в качестве "решения". Однако Java и С# имеют отверстия в своей системе типов (ковариация массива). С++ не имеет этой проблемы.

EDIT: примеры на С++, пытаясь использовать ковариацию массива, которая (неправильно) будет разрешена системами типа Java и С#.

#include <stdlib.h>

struct Base {};
struct Derived : Base {};

template<size_t N>
void func1( Base (&array)[N] );

void func2( Base** pArray );

void func3( Base*& refArray );

void test1( void )
{
  Base b[40];
  Derived d[40];

  func1(b); // ok
  func1(d); // error caught by C++ type system
}

void test2( void )
{
  Base* b[40] = {};
  Derived* d[40] = {};

  func2(b); // ok
  func2(d); // error caught by C++ type system

  func3(b[0]); // ok
  func3(d[0]); // error caught by C++ type system
}

Результаты:

Comeau C/C++ 4.3.10.1 (Oct  6 2008 11:28:09) for ONLINE_EVALUATION_BETA2
Copyright 1988-2008 Comeau Computing.  All rights reserved.
MODE:strict errors C++ C++0x_extensions

"ComeauTest.c", line 19: error: no instance of function template "func1" matches
          the argument list
            The argument types that you used are: (Derived [40])
        func1(d); // error caught by C++ type system
        ^

"ComeauTest.c", line 28: error: argument of type "Derived **" is incompatible with
          parameter of type "Base **"
        func2(d); // error caught by C++ type system
              ^

"ComeauTest.c", line 31: error: a reference of type "Base *&" (not const-qualified)
          cannot be initialized with a value of type "Derived *"
        func3(d[0]); // error caught by C++ type system
              ^

3 errors detected in the compilation of "ComeauTest.c".

Это не означает, что в системе типа С++ нет никаких дыр, но это показывает, что вы не можете без перезаписывать указатель-на-Derived с указателем на базу, как Java и С# allow.

Ответ 5

Вам нужно было спросить его, что он хотел получить окончательный ответ, или, возможно, предоставить больше контекста для этой цитаты.

Однако совершенно очевидно, что если это фатальный недостаток для С++, болезнь хроническая, а не острая - С++ процветает и постоянно развивается, о чем свидетельствуют текущие усилия Boost и С++ 0x.

Я даже не думаю о том, что C и С++ больше связаны - несколько недель на соответствующих форумах быстро вылечивает одну из путаницы в том, что они представляют собой два разных языка, каждый из которых имеет свои сильные и слабые стороны.

Ответ 6

IMHO "самая сломанная" часть системы типа С состоит в том, что понятия

  • значения/параметры, которые являются необязательными
  • изменяемые значения /pass -by-reference
  • массивы
  • параметры функции не-POD

все сопоставляются с понятием "указатель" на одном языке. Это означает, что если вы получите параметр функции типа X*, это может быть необязательный параметр, можно ожидать, что функция изменит значение, на которое указывает X*, возможно, что существует несколько экземпляров X после того, как указана точка (она открывает, сколько - число может быть передано как отдельный параметр, или какое-то специальное значение "терминатор" может означать конец массива, как в nul-terminated strings). Или параметр может быть просто одной структурой, которую вы не ожидаете изменить, но дешевле передать ее по ссылке.

Если вы получаете что-то типа X**, это может быть массив необязательных значений, или это может быть массив простых значений, и вы ожидаете его изменения. Или это может быть 2d зубчатый массив. Или необязательное значение, переданное по ссылке.

В отличие от этого, возьмите семейство языков ML (F #, OCaML, SML). Здесь эти понятия сопоставляются с отдельными языковыми конструкциями:

  • значения, которые являются необязательными, имеют тип X option
  • значения, которые изменяются/передаются по ссылке, имеют тип X ref
  • массивы имеют тип X array
  • и не-POD-типы могут передаваться как POD. Поскольку они не изменяются, компилятор может передать их по ссылке внутри, но вам не нужно знать об этой детали реализации.

И вы можете, конечно, объединить их, т.е. int optional ref является изменяемым значением, которое может быть установлено ничем или целочисленным значением. int ref optional, с другой стороны, является необязательным изменяемым значением; он может быть ничем (и никто не может его изменить), или это может быть некоторый mutable int (и вы можете изменить его на любой другой изменяемый, но не на ничего).

Эти различия очень сублимированы, но вы должны сделать их, программируете ли вы в ML или нет. В C вы должны делать одни и те же различия, но они явно не указаны в системе типов. Вы должны внимательно прочитать документацию, или вы можете ввести ошибки под заголовком (читать: трудно найти), если вы неправильно понимаете, какое использование указателя означает, когда.

Ответ 7

Здесь "коррумпированный" означает, что он не является "строгим", что приводит к бесконечному восторгу в С++ (из-за множества настраиваемых типов (объектов) и перегруженных операторов литье становится высшей неприятностью в С++).

Нападение против C происходит в отношении его ЗАМЕНЯЕМОГО ИСПОЛЬЗОВАНИЯ как строгая основа ООП.

C никогда не предназначался для ограничения кодировщиков, следовательно, может быть, разочарование Академии (и яркое великолепие ++, данное миру Б.С.).

"Я придумал термин Object-Oriented, и могу сказать, что у меня не было С++"

(Алан Кей)