3

So I have only been learning C for about 3 weeks now and I am using this tutorial to help me understand pointers.

I am writing everything the same as he is but I am using Putty and Vim to write my code. When I compile my code however, it says "warning: format '%p' expects argument of type 'void *'". Why do I have to cast to type 'void *' when in the tutorial he doesn't?

int main()
{
    int tuna = 19;
    int *pTuna = &tuna;

    printf("Address \t Name \t Value \n");
    printf("%p \t %s \t %d \n", pTuna, "tuna", tuna);

    return 0;
}

I have casted pTuna to "void *" and the program compiles and runs fine but I don't understand why and why in the tutorial the casting isn't necessary.

Thank you for answering!

C. Smith
  • 61
  • 6
  • 2
    Just a note, Putty and Vim and not compilers. They are SSH client and text editor respectively. – taskinoor Aug 06 '16 at 03:48
  • 1
    I believe that since `printf` has a variable argument list, the compiler must assume all pointers are `void*` since `printf` has no strict declaration. Therefore you are supposed to cast all pointers to `void*`. Something about my answer here seems incomplete or a bit astray, however... I'm sure somebody smart here can provide a better answer. – yano Aug 06 '16 at 03:49
  • 3
    See https://stackoverflow.com/questions/7290923/when-printf-is-an-address-of-a-variable-why-use-void. In short, it's true that `int *` can be converted to `void *`, but `printf` being a variadic function, there is no implicit conversion. – Alok Singhal Aug 06 '16 at 03:49
  • @taskinoor Oooh, thank you for clarifying that for me :) – C. Smith Aug 06 '16 at 04:12
  • @AlokSinghal Reading the answers to that question makes much more sense now, thank you! And definitely explains why in the tutorial there was no need to cast. – C. Smith Aug 06 '16 at 04:14
  • @C.Smith, actually, there *is* a need for the cast. Otherwise gcc wouldn't warn you (gcc does warn sometimes for well-defined code, but this is not one of those cases). Please read the answer in the link again. – Alok Singhal Aug 06 '16 at 07:25

3 Answers3

1

It is the compiler doing one of its primary jobs and typechecking the values you are telling it to use. pTuna is a pointer to int (e.g. int *) and the %p format specifier expects a generic (or void *) pointer.

The compiler issues a warning about the type mismatch telling you to take a second look at the issue and provide a proper cast of the value that will make use of the %p conversion specifier. You comply:

printf("%p \t %s \t %d \n", (void *)pTuna, "tuna", tuna);

Compile again -- and the warning is gone, the compiler has done its job, and all is well again. (and yes, you could ignore the warning, but if warning and error free compiles are not an absolute personal requirement, that's one that may be worth adding. (Yes, there are some situations where a warning can be a known and unavoidable result of some implementations, but those are few and far between. This one here isn't one of those.

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
  • Don't ignore the warning. The code without the case is likely to work on most implementations, but there's no guarantee that `int*` and `void*` have the same representation and are passed in the same way. A conversion from `int*` to `void*` may be non-trivial, and omitting the cast means that conversion isn't done. – Keith Thompson Aug 07 '16 at 00:35
0

It could be that the tutorial is using a different compiler from the one you are using.

In both cases the program compiles but your compiler gives a warning that the one used in the tutorial probably doesn't.

Another option is that the tutorial uses flags to suppress warnings when compiling. An example is the "-w" flag in GCC that suppresses all warnings.

Either way the printf function expects a "void *" argument when there is a %p, so you should cast it.

Nicola Pedretti
  • 4,831
  • 3
  • 36
  • 42
  • Don't suppress warnings; fix the code. Using the `%p` format with an `int*` argument has undefined behavior, It probably "works" on most implementations, but there's no guarantee that `int*` and `void*` even have the same representations. – Keith Thompson Aug 07 '16 at 00:36
  • I never suggested to do so... I am explaining how a compiler does not return warnings – Nicola Pedretti Aug 07 '16 at 00:58
  • Ok, I misread your answer. Nevertheless, the code in the tutorial has undefined behavior. – Keith Thompson Aug 07 '16 at 01:03
-3

It's just a compiler warning. You should have the compiled binary for the first time.

The compiler complains if the type doesn't match: %p expects void* whereas the argument is of type int*. In this case, it is OK to ignore the warning since you're just printing the base address of a pointer and not doing anything else with it.

That said, it is generally good practice to eliminate compiler warnings because they help you check. However, in practice you may not be able to clear them all especially when you don't own the code and don't want to touch them (e.g. libraries).

Warnings exist to make you think twice but will still get the program compiled.

Wai Leong
  • 328
  • 2
  • 7
  • 5
    This answer advocates undefined behaviour. Yes, on most machines leaving the cast off won't cause trouble, but it's an awful lot better to be correct. – Carl Norum Aug 06 '16 at 03:51
  • On which machines will this not work? It is necessary to understand the difference between compiler warning and compiler error. – Wai Leong Aug 06 '16 at 03:56
  • @WaiLeong in C, this difference is not existing. A C compiler is only forced to issue *diagnostics* when it encounters a constraint violation. So no in the contrary, warnings of a C compiler are as good as errors. Especially beginners should *never* ignore such warnings, until they know exactly what these are about. – Jens Gustedt Aug 06 '16 at 07:26
  • @JensGustedt: There is a distinction between warnings issued for constraint violations (IMHO the should be fatal errors, but the standard permits compilers to be more lax) and warnings issued for other reasons. In this case, there is no constraint violation, and the warning is optional (and not be issued unless the format is a string literal.) – Keith Thompson Aug 07 '16 at 00:38
  • @KeithThompson, passing a value of wrong type to a format specifier has UB. So luckily the compiler "warns" about it. – Jens Gustedt Aug 07 '16 at 06:34
  • @JensGustedt: Absolutely. – Keith Thompson Aug 07 '16 at 06:36