Live data from Hacker News

Function overloading in C

gist.github.com

51–57 of 57 posts

Re: Function overloading in C

#51

Earlier quoted context omitted.

Why the hate over casting malloc? It really is not a huge issue. A related question is why do people use malloc if calloc is available?

Why programmers don't always use calloc: good question. Firstly, anyone who does mallocs a block, and then immediately does a memset(block, 0, size) on that block almost certainly should be using calloc. The Linux kernel has kzalloc for this purpose as an alternative to kmalloc and it's fairly widely used. Sometimes it is inefficient to set something to zero, when that is not the true initial value (some or all of th…

In my experience using malloc over calloc make it much harder to find subtle bugs that result from off by one under set errors (i.e. you malloc 100 bytes, only set 99, and then you later read 100 bytes). When you use malloc the 100th byte is filled with random garbage, while with calloc you get something consistent.

Finding bugs where you write 101 bytes are easy to find with tools like Valgrind, but finding bugs where you malloc and don’t initialise the data structure correctly are a real pain.

Re: Function overloading in C

#52
post #50

Earlier quoted context omitted.

I find the lack of implicit conversion from void * really annoying. Any time I see someone cast the return type of malloc in a .c file, I curse C++ and die a little. This sounds like a trivial thing but it very much changes the feel of the language, namely into one where you need to insert pointless casts to satisfy a whiney compiler.

>it very much changes the feel of the language, namely into one where you need to insert pointless casts to satisfy a whiney compiler You could use the exact same argument against any type-safety feature: inserting "pointless" forward declarations, inserting "pointless" const qualifiers, etc., to "satisfy a whiney compiler." The thing is, implicit conversion from void* is plainly unsound, type theoretically speaking.…

Yes, I'm glad that you can use templates to re-implement operator new [] in a way that is susceptible to integer multiplication overflows.

In all seriousness though, I really mean it when I say I intellectually understand the C++ fan's response to a number of these issues. It took me a long time of writing C but I do understand the template-nerd habitat, and can acknowledge its strengths and use those tricks when working in a .cpp file. What frustrates me is to see the rigidity with which it is followed, and the failure to understand the world in a different way. There is a different world out there that doesn't mind an implicit conversion from void pointers, and they're not "wrong".

Re: Function overloading in C

#53

Earlier quoted context omitted.

> For example, you can't pass the OP's "add" around as a function pointer. To be fair, in C++ you have to say which overload you want to point a function pointer at. So the fact that you have to specify the real function you want to point at, in C, doesn't seem unreasonable.

No, you don't have to say that in C++ and there isn't any way to, in fact. // Well, you do say it ... with type! int (*ptr)(int, int) = add; This will take the address of add(int, int) and not some other add like add(double, double). There is no explicit way to refer to one or the other. You're right in that we can't point to the collection of add functions as such. There is no generic function add of which the overl…

You seem to have changed your mind while writing your response, and you appear to have come to the same conclusion I did.

Personally, when I learned about _Generic, I wondered why the C committee hadn't just adopted C++-style overloading. I'm convinced the reason is to avoid name mangling. The end result is that the programmer does the name mangling "by hand," with natural consequences for doing so.

However, there are some important points, which make _Generic both more flexible than C++ overloading in some ways, and less flexible in other ways:

* _Generic only dispatches based on a single parameter.

* _Generic doesn't have to expand to a function call; it could expand to a format string, for instance (although if a macro, FOO, expands to a string literal you can't put FOO(X) next to another string literal and expect the compiler to join the two strings).

* _Generic doesn't consider type conversions when doing the dispatching.

* _Generic dispatching can be as complex as the programmer wishes (e.g., _Generic(X), switch (sizeof(X)) ...); yes, you start with type, but you don't have to limit yourself to exact matches.

* _Generic can have a "default:" branch; this is possible in C++ but not obvious (have one overload take "..." to guarantee it will be the worst match, and only chosen when there is no other option).

Re: Function overloading in C

#54

Earlier quoted context omitted.

Why programmers don't always use calloc: good question. Firstly, anyone who does mallocs a block, and then immediately does a memset(block, 0, size) on that block almost certainly should be using calloc. The Linux kernel has kzalloc for this purpose as an alternative to kmalloc and it's fairly widely used. Sometimes it is inefficient to set something to zero, when that is not the true initial value (some or all of th…

In my experience using malloc over calloc make it much harder to find subtle bugs that result from off by one under set errors (i.e. you malloc 100 bytes, only set 99, and then you later read 100 bytes). When you use malloc the 100th byte is filled with random garbage, while with calloc you get something consistent. Finding bugs where you write 101 bytes are easy to find with tools like Valgrind, but finding bugs whe…

Valgrind will tell you about reading that 100th uninitialized byte.

Re: Function overloading in C

#55

Earlier quoted context omitted.

Why the hate over casting malloc? It really is not a huge issue. A related question is why do people use malloc if calloc is available?

Probably the best reason to hate it is if you didn't include the right headers and malloc is therefore implicitly defined to return int. That creates a bug on most 64-bit compilers where int is 32 bits. The cast will mask the bug. But more stylistically, let's be honest, something like this is way too verbose: struct foo *bar = (struct foo*)malloc(sizeof(struct foo)); I see code like this often, and I think the only…

Any decent C compiler has a warning for the situation that an external function is called without a prototype declaration having been seen.

GCC also has diagnostics for when a function definition occurs without a declaration.

From GCC man page:

       -Wmissing-prototypes (C and Objective-C only)
           Warn if a global function is defined without a previous prototype
           declaration.  This warning is issued even if the definition itself
           provides a prototype.  The aim is to detect global functions that
           fail to be declared in header files.

       -Wstrict-prototypes (C and Objective-C only)
           Warn if a function is declared or defined without specifying the
           argument types.  (An old-style function definition is permitted
           without a warning if preceded by a declaration which specifies the
           argument types.)

       -Wimplicit-function-declaration (C and Objective-C only)
           Give a warning whenever a function is used before being declared.
           In C99 mode (-std=c99 or -std=gnu99), this warning is enabled by
           default and it is made into an error by -pedantic-errors. This
           warning is also enabled by -Wall.

Re: Function overloading in C

#56
post #50

Earlier quoted context omitted.

>it very much changes the feel of the language, namely into one where you need to insert pointless casts to satisfy a whiney compiler You could use the exact same argument against any type-safety feature: inserting "pointless" forward declarations, inserting "pointless" const qualifiers, etc., to "satisfy a whiney compiler." The thing is, implicit conversion from void* is plainly unsound, type theoretically speaking.…

Yes, I'm glad that you can use templates to re-implement operator new [] in a way that is susceptible to integer multiplication overflows. In all seriousness though, I really mean it when I say I intellectually understand the C++ fan's response to a number of these issues. It took me a long time of writing C but I do understand the template-nerd habitat, and can acknowledge its strengths and use those tricks when wor…

My point isn't about templates or memory allocation (hence the code that doesn't check for overflow or worry about object construction). It's that implicit casts from void* are unnecessary in C++, addressing your complaint that it's annoying not to have them. My point is that the lack of implicit casts from void* should not be frustrating, because there are in what are by far the most common use cases equally convenient ways of doing the job.

>What frustrates me is to see the rigidity with which it is followed, and the failure to understand the world in a different way. There is a different world out there that doesn't mind an implicit conversion from void pointers, and they're not "wrong".

I have seen and lived in the world where casts from void* are common, and where making those casts implicit is a convenience (and that world is not the world of C++). I understand that world. I understand that viewpoint. I just strongly disagree with it.

Re: Function overloading in C

#57
post #56

Earlier quoted context omitted.

Yes, I'm glad that you can use templates to re-implement operator new [] in a way that is susceptible to integer multiplication overflows. In all seriousness though, I really mean it when I say I intellectually understand the C++ fan's response to a number of these issues. It took me a long time of writing C but I do understand the template-nerd habitat, and can acknowledge its strengths and use those tricks when wor…

My point isn't about templates or memory allocation (hence the code that doesn't check for overflow or worry about object construction). It's that implicit casts from void* are unnecessary in C++, addressing your complaint that it's annoying not to have them. My point is that the lack of implicit casts from void* should not be frustrating, because there are in what are by far the most common use cases equally conveni…

> It's that implicit casts from void* are unnecessary in C++

Very well aware of the C++-head's answer to these problems.

> My point is that the lack of implicit casts from void* should not be frustrating,

This was a discussion about whether or not C++ is a superset of C. I wrote up the difference that frustrates me the most and all other comments were missing.

Post reply on HN