-2

How can I make gcc warn when a void* is assigned or passed as a parameter to a type that is a more specific kind of pointer, like my_struct* without a cast? I would like to make sure all casting is explicit.

Update: The scope of this question has been extended to non-gcc linters as well.

Update2: Minuses everywhere? I'm flummoxed by the amount of controversy that a simple, purely technical question can generate.

DepressedDaniel
  • 266
  • 1
  • 11
  • Have you read through [GCC's Warnings documentation](https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html)? – Gab Mar 08 '17 at 05:15
  • @GabrieleB-David Yup. – DepressedDaniel Mar 08 '17 at 05:19
  • have you tried using the -Wall flag during compilation and see if it catches that? – Gab Mar 08 '17 at 05:24
  • @GabrieleB-David Yes, I have. I always use both `-Wall` and `-Wextra` for my own programs (with `-Wno-unused-function` because that's just too annoying). – DepressedDaniel Mar 08 '17 at 05:27
  • As far as I know, the only flag that has to do with pointer casting is `-Wint-to-pointer-cast` (which is on by default). – Gab Mar 08 '17 at 05:31
  • 1
    @GabrieleB-David I guess the obvious workaround is `typedef { } opaque_t` and use `opaque_t*` everywhere instead of `void*` but I will leave this open if someone has a better idea or knows of a non-`gcc` linter that can do this check. – DepressedDaniel Mar 08 '17 at 05:38
  • 2
    @GabrieleB-David: `void *` can be assiggned to any other pointer type in C. OP asks about warning for a legal expression whihc does not make sense. – too honest for this site Mar 08 '17 at 06:15
  • 2
    @DepressedDaniel: That would violate the effective type rule, thus invoke UB. Just introduce a coding style guide and tgrust your peers. There are enouigh other things in C you can shoot your feet, arms and head. If you already have a problem with that, you should think about using a strongly typed language. Ada comes into mind, or Python (whereas from your question I suspect a dynamically typed language would be a problem of coding discipline, too). – too honest for this site Mar 08 '17 at 06:17
  • `-Wc++-compat`, but it will also add a number of other warnings. – Marc Glisse Mar 08 '17 at 06:37
  • There isn't a clean solution for this. I suggest you stop using void*, and the problem disappears. – 2501 Mar 08 '17 at 08:03
  • @2501 So what should I use for pointers where I don't know the exact type? – DepressedDaniel Mar 08 '17 at 08:04
  • @DepressedDaniel Can you describe a scenario where you don't know the types of the objects you're defining? – 2501 Mar 08 '17 at 08:05
  • @2501 When something has to work for arbitrary types, consider, e.g., `qsort`. – DepressedDaniel Mar 08 '17 at 08:07
  • @DepressedDaniel But you know the types in that case. It is just that the information is lost when you pass then to qsort. And at that point you shouldn't care anymore since qsort doesn't return anything. – 2501 Mar 08 '17 at 08:09
  • If those predefined functions, where you're unable to change their type, are the problem, then define function wrappers, with a proper type, which will give out a warning. – 2501 Mar 08 '17 at 08:11
  • @2501 Alright, instead of `qsort`, consider `bsearch` ... and defining function wrappers for everything is a lot more overkill than adding a few explicit casts where necessary. – DepressedDaniel Mar 08 '17 at 16:44

2 Answers2

0

How can I make gcc warn when a void* is assigned or passed as a parameter to a type that is a more specific kind of pointer

Being able to assign a void * to a more-specific type without a cast is a required part of the C programming language. Per Paragraph 1 of 6.3.2.3 Pointers of the C Standard:

A pointer to void may be converted to or from a pointer to any object type. A pointer to any object type may be converted to a pointer to void and back again; the result shall compare equal to the original pointer.

You're asking to be warned about a required part of C. It's not far removed from asking for a warning when 5 is assigned to an int.

As noted by @MarcGlisse, though, GCC does provide the -Wc++-compat warning option:

-Wc++-compat (C and Objective-C only)

Warn about ISO C constructs that are outside of the common subset of ISO C and ISO C++, e.g. request for implicit conversion from void * to a pointer to non-void type.

Andrew Henle
  • 32,625
  • 3
  • 24
  • 56
  • Er, you do realize that when things are illegal, compilers try to report errors, and warnings are usually about things that are legal (but suspicious)? Being a "required part of C" is not an argument not to warn. Being a best-practice / common idiom is a better reason. – Marc Glisse Mar 08 '17 at 13:15
  • @MarcGlisse In C it is not only perfectly acceptable to assign a `void *` pointer *without a cast*, it's actually preferable in many ways. The [highest ranked answer](http://stackoverflow.com/a/605858/4756299) on [the fourth-highest ranked question on all of Stackoverflow](http://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc) specifically states to assign `void *` to specific pointer types *without a cast*. Casting `void *` is **not** a "best practice" in C, and there are significant arguments for not casting. Again, it's like asking for a warning on `int x = 5;`. – Andrew Henle Mar 08 '17 at 13:29
  • I agree that warning on this would be wrong. What I said is that "a required part of C" is the wrong argument, what you just wrote in the comment is a much stronger argument. – Marc Glisse Mar 08 '17 at 13:43
  • @MarcGlisse My point in saying "a required part of C" is that a warning would be absurd on code where the syntax is literally *required* to be supported by the language standard. In this case it's the assignment of a `void *` without a cast to a specific type of pointer. 6.3.2.3 requires that such an assignment can be done in C without a cast. – Andrew Henle Mar 08 '17 at 14:25
  • 1
    The semantics of `a&&b||c` are a required part of C and gcc still warns about missing parentheses. Unused variables are a required part of C and gcc still warns. etc. In first approximation: illegal -> error, legal (but questionable) -> warning. – Marc Glisse Mar 08 '17 at 15:19
  • @AndrewHenle -1 I don't usually like to be negative but such a warning has clear upsides - the reason I asked this question is because I had just finished spending time debugging a program where the exact problem was that a `void*` was silently cast to a different type without actually being of that type. Since there are pros and cons either way, the choice should rest with the programmer as which kind of error is more likely ultimately depends on the characteristics of the program's design. And as to the argument that it's a required standard - well, so is `gets`. Nuff said. – DepressedDaniel Mar 08 '17 at 16:33
  • @DepressedDaniel *-1 I don't usually like to be negative but such a warning has clear upsides* The C language mandates that `void *` can be assigned to any type of pointer. The fact that a programmer *put an incorrect cast in place* is not the fault of the language - and the cast would have eliminated any warning anyway. Ever hear the phrase ["a bad workman always blames his tools"?](https://en.wiktionary.org/wiki/a_bad_workman_always_blames_his_tools) If C is the wrong tool for you to use - as stated in the comments - **don't use it**. – Andrew Henle Mar 08 '17 at 18:25
  • @AndrewHenle You're not on point with your logic. The problem was not that a programmer *put an incorrect cast in place*. There was no cast at all. `foo* f; bar* b; void* x; x = f; b = x;` succeeds without any cast and that is a Bad Thing. – DepressedDaniel Mar 08 '17 at 20:53
  • @DepressedDaniel *You're not on point with your logic. The problem was not that a programmer put an incorrect cast in place. There was no cast at all. `foo* f; bar* b; void* x; x = f; b = x;` succeeds without any cast and that is a Bad Thing.* That's ***NOT*** a "bad thing", that's C: **A pointer to `void` may be converted to or from a pointer to any object type.** Again you're blaming the tool for doing *exactly* as the governing standard for that tool says it *must*, And a lot of other programmers believe it is *better* to assign a pointer to `void *` *without* a cast. – Andrew Henle Mar 09 '17 at 00:19
  • @AndrewHenle This is turning into a bit of a flamewar. I'm not blaming the tool, in fact I'm happy with `gcc` since it can actually do the check, and it now enabled in my build. There is a strong technical reason not to want to allow silent conversion of `void*` to any other pointer type - while on the other side the best arguments are "that's the standard" and "other people think it's better [for no articulable reason]". Come on. – DepressedDaniel Mar 09 '17 at 00:34
  • 1
    @DepressedDaniel why are you using void* at all? The main point of void* is the implicit conversions. Otherwise, you could just use char*. – Marc Glisse Mar 09 '17 at 06:54
  • @MarcGlisse Well for arbitrary binary data I don't think `char*` is advisable since it can end up fed into the `str*` functions that operate on null-terminated strings. Really I'm quite happy with the `-Wc++-compat` solution it gives me the right kind of safety net from the type system. – DepressedDaniel Mar 09 '17 at 06:59
  • @DepressedDaniel *I'm not blaming the tool* yet *while on the other side the best arguments are "that's the standard"*?!? The C Standard specifies how this tool must behave to be standard C. Yet you don't like that behavior and want something different? How is that not blaming the tool? So you spent time fixing a bug *where the exact problem was that a `void*` was silently cast to a different type*? Well, C is an unforgiving tool when the programmer *loses track of what he's working with*. Seems like you want a more forgiving tool, which has already been noted. You seem to *want* not-quite-C. – Andrew Henle Mar 09 '17 at 10:55
-1

As noted by @MarcGlisse, gcc provides the -Wc++-compat warning option. Among other non-C++-compatible constructs, it warns about silent conversion of void*.

@AndrewHenle linked to an answer to another question which indicates that requiring an explicit cast has the downside of increasing the likelihood that incompatible conversion may result, for example, if the programmer accidentally casts a numeric value.

I think that's significantly less of a concern, since by an explicit cast the programmer certifies that they know what they're doing. Neverthless, even that small drawback can be addressed by using the following macro in conjunction with -Wc++-compat:

#define VOID_CAST(T, x) ({ __typeof__(x) void_cast_x __attribute__((__unused__)) = ((__typeof__(x))((void*)(x))); ((T*)(x)); })

With luck, the "useless" assignment will be optimized out and the benefit of using VOID_CAST is that it will generate an error or warning if x is not a void* to begin with.

DepressedDaniel
  • 266
  • 1
  • 11