Объясните: «С принципиально имеет поврежденную систему типов» - PullRequest
23 голосов
/ 08 ноября 2010

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

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

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

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

Edit :

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

  2. Пожалуйста, приведите примеры в C , а не C ++ .Меня тоже интересует "принципиально" часть:)

Ответы [ 7 ]

19 голосов
/ 08 ноября 2010

Очевидные примеры 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 не являетсяабсолютно безопасны.

C ++ не полностью безопасен для типов.

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;

Нет проблем с преобразованием Производных * в Основу *, но вы сталкиваетесь с проблемами при попытке использовать Основу * в качествемассив, поскольку он получит неверную арифметику указателя, и в то время как все значения b равны 1, вы вполне можете получить 3 (поскольку целые числа будут идти 1-3-1-3 и т. д.)

5 голосов
/ 08 ноября 2010
char buffer[42];
FunctionThatDestroysTheStack(buffer);  // By writing 43 chars or more
4 голосов
/ 08 ноября 2010

По сути, вы можете привести любой тип данных к любому типу данных

struct SomeStruct {
    void* data;
};

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

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

3 голосов
/ 08 ноября 2010

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

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

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

РЕДАКТИРОВАТЬ: Примеры в C ++, пытаясь использовать ковариацию массива, которая (неправильно) будет разрешена системами типов Java и C #.

#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".

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

2 голосов
/ 08 ноября 2010

ИМХО "самая сломанная" часть системы типов C состоит в том, что понятия

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

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

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

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

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

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

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

2 голосов
/ 08 ноября 2010

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

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

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

1 голос
/ 08 ноября 2010

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

Атака на С относится к его ИСПОЛЬЗОВАНИЮ в качестве строгой ООП.

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

«Я придумал термин« объектно-ориентированный », и могу сказать, что я не имел в виду C ++»

(Алан Кей)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...