5

I have the following code in the C header

typedef struct {
    kiss_fft_scalar r;
    kiss_fft_scalar i;
} kiss_fft_cpx;

And I implemented the following code in the test program

kiss_fft_cpx *fin = malloc(4*sizeof(kiss_fft_cpx));

And it gave me the error message: "A value of type void cannot be used to initialize an entity of type 'kiss_fft_ctx' ".

I am using Visual Studio C/C++ win32 console project.

Can anyone tell me how to correctly use the malloc here? Thanks!

Yang
  • 7,712
  • 9
  • 48
  • 65
Cancan
  • 691
  • 3
  • 14
  • 23
  • possible duplicate of [invalid conversion from 'void\*' to 'node\*' \[-fpermissive\]](http://stackoverflow.com/questions/16793587/invalid-conversion-from-void-to-node-fpermissive) – Keith Thompson Aug 04 '13 at 19:46
  • 2
    I don't think the error message was `void cannot be used to initialize kiss_fft_ctx`. I think it was `void*` and `kss_fft_ctx*`. Those asterisks make a **BIG** difference in the meaning and your understanding of the language. – abelenky Aug 04 '13 at 23:07

2 Answers2

13

You need to cast the return type like this:

kiss_fft_cpx *fin = (kiss_fft_cpx*) malloc(4*sizeof(kiss_fft_cpx));

but the implication is that you're compiling your code as C++ rather than C, because that's a C++ error rather than a C error. You might want to check your file extension and/or your compiler settings.

If you really are using C++, you should at a minimum use new rather than malloc:

kiss_fft_cpx *fin = new kiss_fft_cpx[4];

and ideally rethink whether you need to be creating objects dynamically like this - could you be using a std::vector or similar instead?

RichieHindle
  • 272,464
  • 47
  • 358
  • 399
  • Cool, the problem is that I have to use a C code programmed by others in my c++ project. So, I am wondering if it's also possible to use other scheme rather than malloc to finish the memory allocation.(Otherwise, C++ seems to be pretty dumb here when we use C in C++) – Cancan Aug 04 '13 at 19:42
  • 4
    @Cancan It is, but you better not. Just compile as C instead. **Don't EVER try to compile C code as C++.** They're different languages. –  Aug 04 '13 at 19:43
  • @Cancan For a pure C project, when you compile in C mode and not C++ mode, then the code you have is correct. – Some programmer dude Aug 04 '13 at 19:43
  • Beat me to it. Usually, this kind of direct typecasting is considered unsightly. Make sure it knows you're compiling C, and it won't be required. If you ARE compiling in C++, use new[]. – BrainSteel Aug 04 '13 at 19:43
  • 2
    Also, @RichieHindle: "You need to cast the return type like this" - no, that's wrong - he needs to change compiler instead. –  Aug 04 '13 at 19:43
  • @H2CO3 Yea, I know, but in many real situations, we need to use some handy C code in C++, as we sometimes also need to invoke some useful python code in C++. (Cuz I indeed saw many people do that!) – Cancan Aug 04 '13 at 19:47
  • @Cancan The two situations can't even be compared. You don't "use C code in C++". You don't **have to** compile a C source file with a C++ compiler just because you are working on an otherwise mostly C++ project. You use different compilers for different languages and files. Just like you can write a web page using PHP and JavaScript, yet you are not trying to run the PHP code through the JavaScript engine... –  Aug 04 '13 at 19:49
  • @H2CO3 So, what you mean is that even in one project, there are many different files such as .c .cpp, although they can interact with each other, in real process, they actually only pass through their own compiler, right? – Cancan Aug 04 '13 at 19:51
  • 1
    @Cancan Yes, exactly. Nothing else would really make sense. –  Aug 04 '13 at 19:52
  • @RichieHindle, so can I understand what you said in this way, if we want to use other functions in some other languages in C++, such as C in our case, the way of allocating memory won't conflict and we can just use all the containers or array possible in C++? – Cancan Aug 04 '13 at 19:58
  • 1
    @Cancan: It depends how you use the objects and containers. If you need to manipulate the containers in C, you can't use C++ containers. But if you just need to pass pointers to the objects themselves from C++ into C, it doesn't matter what container they're in. You can even pass a `std::vector` from C++ into C as a plain old array by using `&v[0]` (or using `data()` in C++11) as long as the C code doesn't try to modify the array. – RichieHindle Aug 04 '13 at 20:06
3

In C you can cast the void pointer returned by malloc. C does this for you but you can also be explicit.

malloc returns a void * or void pointer, this returned value can then be cast by a programmer into other pointer types. Or the programmer can rely on C to do the type conversion. C's type conversion using casts is not expected to change.

However, C code that relies on the C-compiler can be obstuse and difficult to read. A development programmer can help maintenance programmers who will eventually have to read the code.

Adding an explicit cast to the returned value of malloc helps humans who will have to read the code and determine the author's intent. This is the real benefit of explicitely casting the void pointer returned by malloc. This programming practice does NOT mis-direct the compiler or make use of some arcane compiler feature that might change.

The following three examples highlight this programming practice. In the first example, malloc (which is defined in <stdlib.h>) is explicitely cast and some trivial work is performed.

   #include <stdlib.h>
   #define nr_chars 4
   main()
   {
    char *data;

    data = (char *) malloc(nr_chars*sizeof(char));

    *data++ = 'a';
    *data++ = 'b';
    *data++ = 'c';
    *data++ = '\0';    // it is allowed to go one past an array

    data -= nr_chars;  // back to the front of data

    printf("%s\n", data);
    // prints abc at the console

   }

In this second example, the only difference is that <stdlib.h> is commented out. The code still runs and produces the same result. Now, the "why" of why this works is fairly direct. When C does NOT find the prototype for a function it assumes that the function returns an int, but malloc returns a void pointer. In this case the explicit cast has told the C compiler, as well as the source's carbon unit, that the value returned by malloc should be converted into a character pointer.

   //#include <stdlib.h>
   #define nr_chars 4
   main()
   {
   char *data;

   data = (char *) malloc(nr_chars*sizeof(char));

   *data++ = 'a';
   *data++ = 'b';
   *data++ = 'c';
   *data++ = '\0';    // it is allowed to go one past an array

   data -= nr_chars;  // back to the front of data

   printf("%s\n", data);
   // prints abc at the console

   }

The final (yeah) example does NOT issue the cast and does not include <stdlib.h>. Both the Eclipse editor and the compiler complain about this code (as they should). The compiler message is

   ..\main.c(18) : warning C4047: '=' : 'char *' differs in levels of indirection from 'int'

And the source code is:

   //#include <stdlib.h>
   #define nr_chars 4
   main()
   {
   char *data;

   data = malloc(nr_chars*sizeof(char));

   *data++ = 'a';
   *data++ = 'b';
   *data++ = 'c';
   *data++ = '\0';    // it is allowed to go one past an array

   data -= nr_chars;  // back to the front of data

   printf("%s\n", data);
   // compiler displays a "warning" and prints abc at the console

   }

Changing example 3 to include results in no warnings and the program runs as intended. However, both examples 2 and 3 lack the explicit cast and over the lifetime of code written in this style such code will be more expensive and more likely to be changed incorrectly by humans (thus the additional expense) than explicit using casts which are supported by C-compilers.

JackCColeman
  • 3,777
  • 1
  • 15
  • 21