I've been reading the implementation of the _countof
macro in MSVC and found a detail I can't explain. It's implemented via a __crt_countof
macro which on C++ is expanded to (sizeof(*__countof_helper(_Array)) + 0)
(here's the relevant code from the header). Why is + 0
there? What would go amiss without it?
Why does the MSVC _count_of implementation add 0 to the result of sizeof? [duplicate]
Asked Answered
The + 0
is added to prevent a potential occurrence of the Most Vexing Parse! Without it, an expression like sizeof(*__countof_helper(_Array))
could be taken as a function declaration in some circumstances.
EDIT: I'm currently trying to work up an example context (as per request in the comment). In the meantime, this much-simplified 'equivalent' (something I have actually encountered) may be helpful:
#include <iostream>
#include <vector>
int main() {
int num = 2;
// std::vector<char> vec(size_t(num)); // Won't compile - Most Vexing Parse
std::vector<char> vec(size_t(num) + 0); // Compiles - no longer a func decl!
vec[0] = 'a';
vec[1] = 'b';
std::cout << vec[0] << ' ' << vec[1] << std::endl;
return 0;
}
Can you share an example of a context where this happens? –
Saville
Extra parenthesis around
size_t(num)
also fixes it, which the macro has. So it looks to me like the macro already defends against that without +0
. –
Saville @FrançoisAndrieux But the M/S coder who implemented that particular header may not have been sure, so added the
+0
just to be on the safe side? –
Jeaninejeanlouis Definitely a possibility. The intention may have been to prevent mvp. In any case it does no harm and it makes sense that nobody wants to take on the responsibility of removing it and risking breaking someone's code by accident if it turns out it does do something unexpected. –
Saville
@FrançoisAndrieux One could maybe 'break' the added parentheses by trying to define a cast/converter operation with:
#define BESILLY(arg) int _countof(arg)
–
Jeaninejeanlouis sizeof
is not size_t
. It's not a type. I don't see how it could ever trigger the MVP. –
Gaultheria @Gaultheria Exactly the point. My efforts to devise an example have so far failed! I can make it happen with
size_t
but not with sizeof
! Here, I can only suggest there may have been a time (still could be, somewhen?) when sizeof
was implemented function-style. And let's not forget that it's best not to "fix" other folks' code if you don't know why you're 'fixing' it. –
Jeaninejeanlouis Can you cite any source that this is the reason for it? The guy who actually wrote the code says differently. –
Agneta
@Agneta I can only refer the caller to my comment, above, or maybe to this alternative: https://mcmap.net/q/1147741/-what-39-s-the-purpose-of-dummy-addition-in-this-quot-number-of-elements-quot-macro –
Jeaninejeanlouis
© 2022 - 2024 — McMap. All rights reserved.
__countof_helper
declaration... – Callawaychar
s as in the argument array. Thussizeof
of thatchar
array should be the same as number of elements in the argument array. – Bonnell+0
. Couldn't__countof_helper
just return_SizeOfArray
? – Savillesizeof(a) / sizeof(a[0])
. If you accidentally pass a pointer instead of a static array to that construct, you'll get bad result. Linked implementation won't compile for a pointer. Here's similar impl in Chromium and here's an article which contains full explanation why something like this is preferable and less error-prone (dare I even say, error free). – Bonnellconstexpr
. And the code I linked compiles but it wouldn't actually run. I see now why it does it this way. It communicates the size through type information which keeps it a compile time constant. – Saville