C-код не работает, когда кодируется как C ++ - PullRequest
2 голосов
/ 02 августа 2011

Привет, разработчики!Я изучаю алгоритмы из книги «Руководство по разработке алгоритмов» Skiena.Там у меня есть следующий код:

    #include <stdio.h>
#include <stdlib.h>

typedef int item_type;

typedef struct{
    item_type item;
    struct list* next;
    }list;

void insert_list(list **l, item_type x){
    list *p;
    p = malloc(sizeof(list));
    p->item = x;
    p->next = *l;
    *l = p;
    }

int main(){
    return 0;
    }

Это дает мне предупреждение при компиляции:

gcc -Wall -o "test" "test.c" (в каталоге: /home / akacoder / Desktop / Algorithm_Design_Manual / chapter2) test.c: в функции 'insert_list': test.c: 15: warning: назначение из несовместимого типа указателя Компиляция успешно завершена.

Но когда я переписываюэтот код как C ++:

 #include <iostream>
#include <cstdio>
#include <cstdlib>
using namespace std;

typedef int item_type;

typedef struct{
    item_type item;
    struct list* next;
    }list;

void insert_list(list **l, item_type x){
    list *p;
    p = malloc(sizeof(list));
    p->item = x;
    p->next = *l;
    *l = p;
    }

int main(){
    return 0;
    }

Он дает следующее:

g ++ -Wall -o "chapter2" "chapter2.cpp" (в каталоге: / home / akacoder /Desktop / Algorithm_Design_Manual / chapter2) chapter2.cpp: 15: ошибка: конфликтующее объявление 'список структур typedef' chapter2.cpp: 14: ошибка: в 'списке структур' есть предыдущее объявление как "список структур" chapter2.cpp: In function 'void insert_list (list **, item_type) ': chapter2.cpp: в функции' void insert_list (list **, item_type) ': chapter2.cpp: 19: ошибка: недопустимое преобразование из' void * 'в' list * '

Кто-нибудь может объяснить, почему это так?И как я могу переписать это в C ++?

Ответы [ 8 ]

9 голосов
/ 02 августа 2011

Это связано с тем, что c ++ является более строгим, чем c, относительно преобразований типов.

В вашем коде множество других ошибок.Обратите внимание, что простое размещение исходного кода переменного тока, переименование файла как .cpp и компиляция с использованием g++ не делает исходный код переменного тока как c ++.

Если вы пишете программу на c++, используйте new & not malloc, при этом вам не нужно явно набирать приведение, как в случае malloc.

8 голосов
/ 02 августа 2011

Ваша проблема в обоих случаях заключается в определении структуры: struct list *next не относится к структуре, в которой вы находитесь в процессе объявления. Попробуйте вместо этого:

typedef struct list {
    item_type item;
    struct list* next;
} list;

Кроме того, в C ++ вы должны приводить void *, возвращаемый malloc, к соответствующему типу указателя (list *), C ++ более строг в этих вещах. Кроме того, кстати, в C ++ вы можете полностью исключить typedef, если хотите.

Причиной различий в сообщениях об ошибках является различие в языках.

В Си компилятор знает, что struct list * является указателем на структуру, поэтому ему не нужно жаловаться, что он на самом деле не знает, что такое "список структуры". Однако позже, когда вы пытаетесь присвоить этот «список структуры *» из указателя типа «список *» (типом которого является «указатель на анонимную структуру»), он жалуется на несоответствие.

В C ++ объявление "struct" более или менее эквивалентно объявлению "class" (основное отличие заключается в видимости членов по умолчанию). Среди прочего, это означает, что структуры в C ++ более или менее автоматически определяются по типу. Поэтому, когда компилятор видит «struct list * next», он воспринимает это как предварительное объявление класса с именем «list»; затем, когда он заканчивает оператор и обрабатывает typedef, выдает ошибку, потому что вы пытаетесь что-то определить с помощью идентификатора, который уже (forward-) объявлен как что-то еще. Затем он выдает дополнительные ошибки, потому что фактически не знает, что может быть «список», из-за более ранней ошибки.

5 голосов
/ 02 августа 2011

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

Просто добавьте приведение, и оно решит оба сообщения:

p = (list*)malloc(sizeof(list));

Или, если вы хотите быть только C ++:

p = new list;

Но тогда вы должны объявить конструкторов и тому подобное.

4 голосов
/ 02 августа 2011

Это объяснено в этой ссылке .

Цитата:

Принято для программиста C ++, использующего C

Structs and Enums

Вы должны включить ключевое слово struct перед именем типа struct, чтобы объявить struct: в C ++ вы могли бы сделать это

struct a_struct { int x; };

a_struct struct_instance;

и имеют новый экземпляр a_struct с именем struct_instance.В C, однако, мы должны включить ключевое слово struct при объявлении struct_instance:

struct a_struct struct_instance;

На самом деле, аналогичная ситуация также имеет место для объявления перечислений: в C,Вы должны включить ключевое слово enum;в C ++ вам не нужно.В качестве примечания, большинство программистов на C решают эту проблему, используя typedefs:

typedef struct struct_name {/ * variable * /} struct_name_t;

Теперь вы можете объявить struct с помощью

struct_name_t struct_name_t_instance;

Но есть еще одна проблема для программистов на C ++: вы все равно должны использовать синтаксис "struct struct_name" для объявления члена struct, который является указателем на struct.

typedef struct struct_name {
    struct struct_name instance;
    struct_name_t instance2; /* invalid!  The typedef isn't defined
yet */ } struct_name_t;
3 голосов
/ 02 августа 2011

Вам нужно изменить этот класс:

typedef struct{
    item_type item;
    struct list* next;
    }list;

на этот:

struct list {
    item_type item;
    list* next;
    };

Объяснение: в первом примере у вас есть анонимная структура, внутри которой struct list впередобъявлен.Поэтому, когда компилятор видит typedef на следующей строке, он обнаруживает конфликт имен, потому что typedef отличается от объявления структуры в C ++.

2 голосов
/ 02 августа 2011

Поскольку то, что вы делаете, на самом деле определяет struct, а затем создает псевдоним с typedef Я думаю, что это более читабельно сделать в случае C:

typedef struct list_ {
    item_type item;
    struct list_* next;
} list;
1 голос
/ 02 августа 2011

Используйте следующий код

#include <iostream>
#include <cstdio>
#include <cstdlib>
using namespace std;

typedef int item_type;

struct list{
    item_type item;
    list* next;
};

void insert_list(list **l, item_type x){ 
    list *p; 
    p = (list*)malloc(sizeof(list));
    p->item = x;
    p->next = *l; 
    *l = p;
}

int main(){
    return 0;
}
0 голосов
/ 02 августа 2011

Что C только предупреждает, C ++, скорее всего, сочтет ошибку.

Это культурная вещь программирования. Си был очень снисходительным, не применяя систему печати. C ++ все еще довольно простителен, но вы делаете что-то в C, что даже C ++ не простит.

Когда вы выделяете этот блок памяти, приводите его к указателю на список. Это преобразует адрес (указатель) в указатель правильного типа.

Без этого приведения вы могли бы иметь значение malloc, равное размеру чего угодно, и невозможно сказать, предполагалось ли на него ссылаться указателем списка или каким-либо другим указателем.

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