isocpp / isocpp/CppCoreGuidelines

P.5: static_assert(sizeof(Int) >= 4) assumes CHAR_BIT = 8, unlike the code it replaces

Open
#1,528 0 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
CSS
Stars
45.3k
Forks
5.6k
PR merge metrics
No merged PRs in 30d

Description

P.5: Prefer compile-time checking to run-time checking has a loop that tries to find the bit width of a signed integer but suffers from signed-overflow UB.

The suggested replacement static_assert(sizeof(Int) >= 4) assumes that bit-width = sizeof(T) * 8. This is not true on some word-addressable DSPs, for example, where sizeof(int) = sizeof(char), and CHAR_BIT is 24 or 32. This would give a false-positive compile-time error which is less bad than letting code compile when it won't work. (CHAR_BIT is required to be at least 8).

static_assert(std::numeric_limits<Int>::digits >= 31) would be correct, I think. Integer types are guaranteed to have radix = 2. digits excludes the sign bit, but the runtime loop was probably assuming 2's or 1's complement (not sign/magnitude) and expecting to count it, too.

sizeof(Int) * CHAR_BIT >= 32 is shorter to type, and I was able to write it without having to check the numeric_limits docs to see which member was the bit-width of integer types. But that's might just be me. And now that I think about it, it's not as portable.

sizeof(Int) * CHAR_BIT assumes there are no padding bits. Any check inferring the number of value bits from the amount of storage isn't safe in general on a DeathStation 9000.


Of course all this complexity about what / how to check starts to make this a less-than-ideal example. A runtime check for endianness or 1's vs. 2's complement (maybe based on ~0) might work better, and use numeric_limits<T>::min() and max() to check for 1's vs. 2's complement. e.g. min+max == -1 means 2's complement. For signed types that won't overflow. For unsigned types we might have a false positive with max() == 0xFFFF... and -1 converted to unsigned gives 0xFFFF...

So I don't have a specific suggestion to replace both examples, but if you think std::numeric_limits<Int>::digits >= 31 will be distracting (e.g. why 31 instead of 32?) then it's worth considering a rewrite.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in the P.5 section of CppCoreGuidelines.md, where the signed-integer bit-width loop and its suggested static_assert replacement are described. Review the portability concerns around CHAR_BIT, padding bits, numeric_limits, and signed representations. Done means updating the example or explanatory text with a technically sound, clear approach; the issue does not prescribe one replacement.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
documentation
Issue type
Documentation
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.