1

On Visual C++ 2019:

The following code renders the warning:

warning C4267: 'argument': conversion from 'size_t' to 'DWORD', possible loss of data

HANDLE events[2];
WaitForMultipleObjects(std::size(events), events, FALSE, INFINITE);

But using _countof(events) won't give any warning. Note that std::size's template overload function is called. This one:

template<class _Ty,
    size_t _Size> inline
    constexpr size_t size(const _Ty(&)[_Size]) _NOEXCEPT
    {   // get dimension for array
    return (_Size);
    }

Which essentially is returning a size_t, and the function is constexpr. And that's why array declaration works:

HANDLE Events[2];
int arr[std::size(Events)];

But following code won't compile without warning:

DWORD sz1 = std::size(Events);

This is okay:

DWORD sz2= _countof(Events);

Any specific reason, or a compiler bug?

Relevant: What is the return type of sizeof operator?

EDIT, Interestingly, these would also work fine:

HANDLE events[2];
constexpr size_t s1 = sizeof(Events) / sizeof(Events[0]);
constexpr size_t s2 = std::size(Events);

The variables s1 and s2 are taken as true compile-time values, but not std::size()'s result itself!

Ajay
  • 18,086
  • 12
  • 59
  • 105
  • "*The variables s1 and s2 are taken as true compile-time values, but not std::size()'s result itself!*" What is a "true compile-time value, and how is `std::size()` different from that? – Nicol Bolas Mar 03 '20 at 14:30
  • @NicolBolas A `constexpr` function may not result in compile-time constant – Ajay Mar 04 '20 at 07:49
  • Yes, `constexpr` functions can be executed at runtime. But that didn't answer my question: what do you consider to be a "true compile-time value"? – Nicol Bolas Mar 04 '20 at 14:44

2 Answers2

0

If you read the warning messages it's a complaint about converting from the type size_t (the result of std::size(Events)) to DWORD (the type of sz1).

The problem is that on a 64-bit system size_t is typically a 64-bit unsigned integer type. But Windows define DWORD as a 32 bit unsigned integer type.

That the use of _countof doesn't generate a warning might be because of implementation-specific behavior of the MSVC compiler.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • This also doesn't answer my question. Why `_countof` or `sizeof/sizeof` at WFSO call would work fine, but not `constexpr std::size()` ? – Ajay Mar 03 '20 at 07:30
0

DWORD is always 32-bit unsigned on Windows.

size_t is typically a 64-bit unsigned long long with a 64-bit compiler. Switch your build to 32-bit and it's a 32-bit unsigned int.

Assigning a 64-bit int to a 32-bit - yep, that's a warning condition.

What's weird is this:

WaitForMultipleObjects(sizeof(events) / sizeof(events[0]), events, FALSE, INFINITE);

Compiles without issue. I'm guessing it's because the compiler can infer the type of that const expression reduces to unsigned int or smaller.

But this:

auto count = sizeof(events) / sizeof(events[0]);
WaitForMultipleObjects(count, events, FALSE, INFINITE);

Generates a nearly identical warning since count evaluates to a 64-bit unsigned long long.

But this will also compile without warning:

const auto count = sizeof(events) / sizeof(events[0]);
WaitForMultipleObjects(count, events, FALSE, INFINITE);
selbie
  • 100,020
  • 15
  • 103
  • 173
  • I'm sorry but it doesn't answer my question. If `sizeof(events) / sizeof(events[0])` is placed at WFMO call, it would compile fine. `_countof`, `ARRAY_SIZE` would also. Why not `std::size` ? – Ajay Mar 03 '20 at 07:29
  • 1
    @Ajay - I see what you are asking. When I step through the assembly in the debugger, it appears that the call to std::size is indeed a function call to the template function in `` and not inlined. – selbie Mar 03 '20 at 07:38
  • Does not explain why it still warrants a warning in release - when it's clearly inlined. – selbie Mar 03 '20 at 07:42
  • `constexpr` function, in that context, is behaving like "consteval". Function call won't be made (there is template based return value resolution). Let it be inline or not, that's for other contexts. BTW, did you see `template []` version for assembly code? – Ajay Mar 03 '20 at 07:47