开发者

C code does not work when coded like C++

Hello Developers! I am learning algorithms from Algorithms Design Manual Book by Skiena. There I have the following code:

    #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;
    }

It gives me Warning when compiled:

开发者_运维问答

gcc -Wall -o "test" "test.c" (in directory: /home/akacoder/Desktop/Algorithm_Design_Manual/chapter2) test.c: In function ‘insert_list’: test.c:15: warning: assignment from incompatible pointer type Compilation finished successfully.

But when I rewrite this code as 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;
    }

It gives the following:

g++ -Wall -o "chapter2" "chapter2.cpp" (in directory: /home/akacoder/Desktop/Algorithm_Design_Manual/chapter2) chapter2.cpp:15: error: conflicting declaration ‘typedef struct list list’ chapter2.cpp:14: error: ‘struct list’ has a previous declaration as ‘struct list’ chapter2.cpp: In function ‘void insert_list(list**, item_type)’: chapter2.cpp: In function ‘void insert_list(list**, item_type)’: chapter2.cpp:19: error: invalid conversion from ‘void*’ to ‘list*’

Can anyone explain why it is so? And How can I rewrite it in C++?


This is because c++ is stricter than c with respect to type conversions.

There are host of other errors in your code. Please note that just putting a c source code, renaming the file as .cpp & compiling using g++ does not make a c source code as c++.

If you are writing a program in c++ please use new & not malloc, doing so you do not need to explicitly type cast as in case of malloc.


Your problem in both cases is in the struct definition: struct list *next doesn't refer to the struct you are in the process of declaring. Try this instead:

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

In addition, in C++ you must cast the void * returned by malloc to the appropriate pointer type (list *), C++ is stricter about these things. Also, BTW, in C++ you can leave off the typedef completely if you want.

The reason for the differing error messages is a difference in the languages.

In C, the compiler knows that struct list * is a pointer to a struct, so it doesn't need to complain that it doesn't actually know what a "struct list" is yet. Later, though, when you try to assign this "struct list *" from a pointer of type "list *" (the type of which is "pointer to an anonymous struct"), it complains about the mismatch.

In C++, a "struct" declaration is more or less equivalent to a "class" declaration (the major difference is in the default visibility of members). Among other things, this means that structs in C++ are more or less automatically typedefed. So when the compiler sees "struct list *next", it takes it as a forward declaration of a class named "list"; then when it finishes the statement and processes the typedef, throws an error because you're trying to typedef something to an identifier that is already (forward-)declared as something else. Then it issues further errors because it doesn't actually know what "list" might be, due to the earlier error.


C++ does not allow arbitrary pointer conversions, while C does. But since this is not considered good style, the compiler emits a warning.

Just add a cast and it will solve both messages:

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

Or if you want to be C++ only:

p = new list;

But then, you should declare constructors and such, also.


This is explained in this link.

Quote:

Gotcha for a C++ programmer using C

Structs and Enums

You have to include the struct keyword before the name of the struct type to declare a struct: In C++, you could do this

struct a_struct { int x; };

a_struct struct_instance;

and have a new instance of a_struct called struct_instance. In C, however, we have to include the struct keyword when declaring struct_instance:

struct a_struct struct_instance;

In fact, a similar situation also holds for declaring enums: in C, you must include the keyword enum; in C++, you don't have to. As a side note, most C programmers get around this issue by using typedefs:

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

Now you can declare a struct with

struct_name_t struct_name_t_instance;

But there is another gotcha for C++ programmers: you must still use the "struct struct_name" syntax to declare a struct member that is a pointer to the struct.

typedef struct struct_name {
    struct struct_name instance;
    struct_name_t instance2; /* invalid!  The typedef isn't defined
yet */ } struct_name_t;


You need to change this class:

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

to this:

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

Explanation: in the first example, you have anonymous structure, inside which struct list is forward declared. So when compiler sees typedef on the next line it finds a name collision, because typedef is not the same as struct declaration in C++.


Since what you're doing is really defining a struct and then creating an alias with the typedef I think it's more readable to do this in the C case:

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


Use the following code

#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;
}


What C only warns against, C++ is likely to consider an error.

It's a programming cultural thing. C was very forgiving in not enforcing it's typing system. C++ is still quite forgiving, but you're doing something in C that even C++ won't forgive.

When you malloc that block of memory, cast it to a pointer to a list. That will covert the address (pointer) to a pointer of the right type.

Without that cast, you could have malloc'd the size of anything, and there's no telling if it was meant to be referenced by a list pointer or some other pointer.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜