2012-05-05 17 views
54

To pytanie zostało wywołane przez odpowiedź (odpowiedzi) na post by Herb Sutter, w której wyjaśnił decyzję MS, aby nie obsługiwać/tworzyć kompilatora C99, ale po prostu idź z funkcjami C (99), które i tak są w standardzie C++ (11).Jakie są niezgodne różnice między C (99) i C++ (11)?

Jeden commenter replied:

(...) C jest ważna i zasługuje przynajmniej trochę uwagi.

Istnieje wiele istniejącego kodu, który jest ważny C, ale nie jest prawidłowy C++. Ten kod najprawdopodobniej nie zostanie przepisany (...)

Ponieważ programuję tylko w MS C++, naprawdę nie znam dobrze "czystego" C, tzn. Nie mam gotowego obrazu tego, jakie szczegóły język C++, którego używam, nie znajduje się w C (99) i mam małe wskazówki, w których niektóre kody C99 nie działałyby tak jak są w kompilatorze C++.

Zauważ, że wiem o C99 tylko restrict słowa kluczowego, które do mnie wydaje mieć bardzo wąskie zastosowanie i o zmiennej długości tablic (z czego nie jestem pewien, jak powszechne lub istotne są).

Również jestem bardzo zainteresowany, czy istnieją jakiekolwiek istotne semantyczne różnice lub pułapek, czyli C (99) kod, który będzie skompilować pod C++ (11), ale coś zrobić inaczej z kompilatora C++ niż z Kompilator C.


Szybkie łącza: środki zewnętrzne z odpowiedzi:

+8

Czy C++ 11 obsługuje tablice o zmiennej długości? C99 ma, więc jeśli nie, to całkiem dobry przykład. –

+2

http://david.tribble.com/text/cdiffs.htm - wiele z nich nadal obowiązuje w C++ 11. @CodyGray: VLA nie są częścią C++ 11. – Mat

+1

@CodyGray: C++ 11 nie obsługuje VLA, więc twój komentarz może być odpowiedzią :) –

Odpowiedz

26

Jeśli zaczniesz od wspólnego podzbioru C i C++, czasami nazywany czyste C (co nie jest całkiem C90), trzeba rozważyć 3 rodzaje niezgodności:

  1. Dodatkowe C++ featues które sprawiają, legal C illegal C++

    Przykładami są słowa kluczowe w C++, które mogą być używane jako identyfikatory w C lub konwersje, które są ukryte w C, ale wymagają jawnej obsady w C++.

    Jest to prawdopodobnie główny powód, dla którego Microsoft w ogóle nie zawiera interfejsu C: w przeciwnym razie starsza wersja kodu, która nie będzie kompilowana jako C++, musiałaby zostać przepisana.

  2. Dodatkowe funkcje C, które nie są częścią C++

    Język C nie zatrzymał się rozwija po C++ został rozwidlony. Niektóre przykłady to tablice o zmiennej długości, oznaczone inicjalizatory i restrict. Funkcje te mogą być bardzo przydatne, ale nie są częścią każdego ++ standard C, a niektóre z nich prawdopodobnie nigdy nie zrobić go w.

  3. funkcje, które są dostępne zarówno w C i C++, ale mają różne semantyka

    Przykładem może być połączenie obiektów const lub funkcji inline.

lista niezgodności między C99 i C++ 98 can be found here (co już zostało wspomniane o MAT).

Podczas gdy C++ 11 i C11 zbliżyły się na niektórych frontach (makra variadyczne są teraz dostępne w C++, tablice o zmiennej długości są teraz opcjonalną funkcją języka C), lista niekompatybilności również się zwiększyła (np. Wybór ogólny w C i specyfikacji typu auto w C++).

Na marginesie, podczas gdy Microsoft wziął trochę energii na decyzję o porzuceniu C (co nie jest ostatnim), o ile wiem, nikt w społeczności open source nie podjął żadnych kroków, by coś z tym zrobić. : Byłoby całkiem możliwe zapewnienie wielu funkcji współczesnego C za pomocą kompilatora C-to-C++, zwłaszcza jeśli wziąć pod uwagę to, że some of them are trivial to implement. Jest to obecnie możliwe dzięki użyciu Comeau C/C++, który obsługuje C99.

Nie jest to jednak nagląca kwestia: Osobiście nie mam problemu z używaniem GCC i Clang na Windowsie, istnieją również zastrzeżone alternatywy dla MSVC, np. Kompilator Pelles C lub Intel.

29

Istnieje kilka niezgodności, które istnieją od wieków (C90 o r wcześniej), a także kilka naprawdę fajnych funkcji w C99 i C11. Te są z góry mojej głowy.

// Valid C 
int *array = malloc(sizeof(*array) * n); 

// Valid C and valid C++, extra typing, it's always extra typing... 
int *array = (int *) malloc(sizeof(*array) * n); 

// Valid C++ 
int *array = new int[n]; 

C99 jest ładne i programistów C wszędzie powinniśmy używać go

nowych funkcji C99 są bardzo miłe dla ogólnego programowania. VLA i restrict nie są (moim zdaniem) przeznaczone do ogólnego użytku, ale głównie do sprowadzania FORTRAN i programistów numerycznych do C (chociaż restrict pomaga autovectorizer). Ponieważ każdy zgodny program, który używa restrict nadal będzie działał dokładnie w ten sam sposób (ale prawdopodobnie nie tak szybko), jeśli na górze pliku znajduje się #define restrict, to nie jest wielka sprawa. VLA są dość rzadkie na wolności, jak się wydaje.

Elastyczne elementy tablicy mogą być ładne. Pamiętaj, że NIE są to te same tablice o zmiennej długości! Ludzie używają tej sztuczki od lat, ale oficjalne wsparcie oznacza mniej pisania, a także pozwala nam tworzyć stałe w czasie kompilacji. (Starym sposobem było posiadanie tablicy wielkości 1, ale obliczenie wielkości alokacji jest prawdziwym problemem.)

struct lenstr { 
    unsigned length; 
    char data[]; 
}; 
// compile time constant 
const struct lenstr hello = { 12, "hello, world" }; 

Wyznaczone inicjalizatory. Zapisuje dużo pisania.

struct my_struct { int a; char *b; int c; const char *d; }; 
struct my_struct x = { 
    .a = 15, 
    .d = "hello" 
    // implicitly sets b = NULL and c = 0 
}; 
int hex_digits[256] = { ['0'] = 0, ['1'] = 1, ['2'] = 2, /* etc */ ['f'] = 15 }; 

inline kluczowe zachowuje się inaczej, można wybrać, które tłumaczenie jednostka dostaje non-inline wersję funkcji zadeklarowanej inline dodając extern deklarację do tej jednostki.

Koncentrat literały.

struct point { float x; float y; }; 
struct point xy_from_polar(float r, float angle) 
{ 
    return (struct point) { cosf(angle) * r, sinf(angle) * r }; 
} 

snprintf funkcja jest prawdopodobnie w moim top 10 najbardziej przydatnych funkcji bibliotecznych w C. To nie tylko brakuje C++, ale runtime MSVC zapewnia tylko funkcję o nazwie _snprintf, która nie jest gwarantowane dodaj terminator NUL do ciągu. (snprintf jest w C++ 11, ale nadal nieobecnosc od wykonywania MSVC C).

anonimowych struktury i związki (rozszerzenie C11, ale od zawsze GCC) (anonimowe związki są najwyraźniej w C + +03, brak wsparcia MSVC w trybie C):

struct my_value { 
    int type; 
    union { 
     int as_int; 
     double as_double; 
    }; // no field name! 
}; 

Jak widać, wiele z tych funkcji tylko zaoszczędzić dużo pisanie (literały złożonych), lub dokonać programy łatwiejsze do debugowania (członkowie elastyczny array) , ułatwiają unikanie błędów (wyznaczają inicjatory/zapominając o inicjalizacji pól struktury). To nie są drastyczne zmiany.

Dla różnic semantycznych, jestem pewien, że reguły aliasingu są różne, ale większość kompilatorów jest wystarczająco wybaczająca w tych dniach Nie jestem pewien, jak skonstruować przypadek testowy do wykazania. Różnica między C i C++, do której wszyscy sięga, to stare wyrażenie sizeof('a'), które zawsze jest 1 dla C++, ale zwykle 4 dla 32-bitowego systemu C. Ale nikomu nie zależy na tym, co jest sizeof('a'). Istnieją jednak pewne gwarancje w standardzie C99, które kodyfikują istniejące praktyki.

Wprowadź następujący kod. Używa wspólnej sztuczki do definiowania typów związków w C bez marnowania dodatkowej pamięci. I think to jest semantycznie poprawne C99 i I myśleć jest to wątpliwy semantycznie C++, ale może się myliłem.

#define TAG_FUNKY_TOWN 5 
struct object { int tag; }; 
struct funky_town { int tag; char *string; int i; }; 
void my_function(void) 
{ 
    struct object *p = other_function(); 
    if (p->tag == TAG_FUNKY_TOWN) { 
     struct funky_town *ft = (struct funky_town *) p; 
     puts(ft->string); 
    } 
} 

Ale szkoda. Generator kodu MSVC jest ładny, szkoda, nie ma front-end C99.

+1

C99 nie pozwala na elastyczną inicjalizację elementu macierzy (jest to rozszerzenie GNU). C++ 11 ma jednolitą inicjalizację, która jest podobna do literałów złożonych: 'return {cos (angle) * r, sin (angle) * r};'. anonimowe związki są prawidłowe C++. Nie jestem pewien, że anonimowe konstrukcje są nawet poprawne C (i wydają się dla mnie bezsensowne). Myślę, że ten "wątpliwy semantycznie C++" jest ważny, ale mogę się mylić. – bames53

+5

Również C++ jest ładne, a programiści C wszędzie powinni go używać. ;) – bames53

+0

"Inline keyword zachowuje się inaczej, możesz wybrać, która jednostka tłumaczeniowa otrzyma nieliniową wersję funkcji zadeklarowanej w tekście poprzez dodanie deklaracji zewnętrznej do tej jednostki.". I niestety Ty [** masz ** to] (http://stackoverflow.com/questions/2217628/multiple-definition-of-inline-functions-when-linking-static-libs/2218034#2218034) wybierz :( –

2

W C++ ustawienie jednego elementu unii i uzyskanie dostępu do wartości innego elementu jest niezdefiniowanym zachowaniem, podczas gdy nie jest niezdefiniowane w C99.

Istnieje wiele innych różnic wymienionych na wikipedia page.

+0

Pomyślałem, że to także UB w C99 i to tylko OpenCL C (który opiera się na C99), który nieco stracił to ograniczenie. –

+1

@ ChristianRau: http: //stackoverflow.com/a/8513748/48015 – Christoph

+0

[sekcja wikipedia (http://en.wikipedia.org/wiki/Compatibility_of_C_and_C%2B%2B#Constructs_valid_in_C_but_not_C.2B.2B) jest rzeczywiście całkiem miło. Powinienem zrobić zwyczaj odwiedzania wikipedii przed pytaniem tutaj. :-) –

2

Wymienię "C.1 C++ i ISO C" z C++11 standard. Ten dokument ma siłę uderzenia każdej różnicy i jej wpływ na rozwój.

Powiązane problemy