5 ms·
This is why for C/C++, I always like to have something like: foo * bar(foo * useme=0); where one can optionally pass memory to be used, but if nothing is pass
by cozzyd 7y ago
This is why for C/C++, I always like to have something like:
foo * bar(foo * useme=0);
where one can optionally pass memory to be used, but if nothing is passed, it will be allocated by the function (placement new can be helpful here!).
- kazinator 7y agoThat can't be "C/C++" because C doesn't have optional parameters. In C++, a better thing would be to take advantage of overloading directly: foo *bar(foo *); // doesn't allocate; non-null required foo *bar(); // allocates Then there is no run-time check of the pointer value for null. bar() is just a wrapper like: foo *bar() { return bar(new Foo); } Moreover, the value provided by bar() is pretty low; it's like a syntactic sugar that rewrites bar() to bar(new Foo). I'd consider not adding that to the API.
- huhtenberg 7y ago> C doesn't have optional parameters You are over-nitpicking. It's obvious that the GP meant that you can pass NULL by default if needed.
- kazinator 7y agoBut when would that be needed? The argument is optional, and null is its default value. But the way the overloads are collapsed into a single function, there has to be a run-time check for that null. Using a null to indicate "argument is not there" is a C API trick. That parameter won't be optional in C.
- kragen 7y agoIf you only have a K&R-style declaration visible, you can still call it with the wrong number of arguments, but (contrary to what you'd expect from doing the same thing in JS or Lua) most C implementations will instead pass some garbage data as the additional parameter, rather than NULL. Also, most C implementations will allow you to cast function pointers in a way that results in calling the function with the wrong number of arguments. If you're especially unlucky, that garbage data will happen to be NULL at first, but then become non-NULL when you recompile with debugging turned off, resulting in truly fascinating ways to spend your Friday and Saturday nights the month before shipping. (I know you know this, Kaz. I'm mentioning this for the benefit of those who haven't yet spent their Friday and Saturday nights this way.)
- MaulingMonkey 7y agoI'd agree if GP hadn't also used C++-specific optional parameters. Given the minefield that is vendor specific C++ish extensions to C, it seems worth a mention, even if I'm unaware of a compiler vendor that allows default parameters in your C code.
- cozzyd 7y agoIt was just an illustration in C++ (the C version would just document it, obviously). There is no way to do this in a vendor specific way without some sort of name mangling that will hopelessly break the ABI...
- a1369209993 7y agoYes there is: void foo(void* p=0); // has exactly the same ABI as void bar(void* p); bar(); // error: missing parameter foo(); // shorthand for foo(0); // void(*)(void*) is a different type than void(*)(void*=0) // but they can be implicitly converted the same as // eg void* and char*
- cozzyd 7y agohmm I guess so!
- wereHamster 7y agoI don't think OP meant that as an optional parameter, but more like: // Definition foo * bar(foo * useme); And then use as // Allocate foo for me pls. foo * result = bar(NULL) or // I'll allocate the buffer myself ktkxbye. foo * result = bar(malloc(…))
- kazinator 7y agoThat's what you'd do in C. Since the malloc return has to be checked, and the object may have to be initialized, the API could provide enough convenience to justify it.
- cozzyd 7y agoYes, I know C has no function overloading (or optional parameters) of course. I didn't feel like writing it out twice though. The pattern is more useful when there are more arguments to foo and you don't want to have bar(int a, int b, double c, foo * useme) and bar(int a, int b, double c) in the API.
- mark-r 7y agoThere's another common C API pattern that I was surprised to not see mentioned. You pass a buffer pointer and the size of the buffer, and the function returns the number of items written to the buffer. If the pointer is null or the size is zero, the return value is the size that you need to allocate to ensure proper function completion.
- mras0 7y agoI'm curious about what kind of situations you're using this pattern in C++. Not objecting to the practice in any way, it's just that I haven't encountered many situations where I wouldn't just have created another function for the allocating case that called the non-allocating one.
- cozzyd 7y agoSomething like... double * doMathOperation(unsigned N, const double * in, double aux1, double aux2, double * out = 0); (obviously, in C, you would leave the = 0 out and document it instead).