C 宏计算给定编译时常量所需的字节数

发布于 2024-09-26 17:08:52 字数 379 浏览 3 评论 0原文

我经常有一些编译时常量,它也是变量假定的可能值的上限。因此,我有兴趣选择可以容纳这些值的最小类型。例如,我可能知道变量将适合 <-30 000, 30 000> 。范围,所以当寻找合适的类型时,我会从有符号的短整型开始。但由于我在平台和编译器之间切换,我想要一个编译时断言来检查常量上限值是否真正适合这些类型。 BOOST_STATIC_ASSERT( sizeof(T) >= required_number_of_bytes_for_number ) 工作正常,但问题是: 如何自动确定存储给定编译时常量(有符号或无符号)所需的字节数?我猜 C 宏可以完成这项工作?有人可以帮我写一下吗? 我可能会使用 std::numeric_limits::max() 和 min() 而不是计算字节,但随后我必须切换到运行时断言:(

Often I have some compile-time constant number that is also the upper limit of possible values assumed by the variables. And thus I'm interested in choosing the smallest type that can accomodate those values. For example I may know that variables will fit into <-30 000, 30 000> range, so when looking for a suitable type I would start with signed short int. But since I'm switching between platforms and compilers I would like a compile-time assert checking whether the constant upper values really fit within those type. BOOST_STATIC_ASSERT( sizeof(T) >= required_number_of_bytes_for_number ) works fine but the problem is:
How to automatically determine the number of bytes required for storing a given compile-time constant, signed or unsigned? I guess a C macro could do this job? Could anyone write it for me?
I might use std::numeric_limits::max() and min() instead of computing the bytes but then I would have to switch to run-time assert :(

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

挽手叙旧 2024-10-03 17:08:52

既然这是用 c++ 标记的,我建议使用 Boost.Integer 进行适当的类型选择。 boost::int_max_value_tboost::int_max_value_t< MyConstant >::least 将给出您正在寻找的类型。

Now that this is tagged with c++, I suggest using Boost.Integer for appropriate type selection. boost::int_max_value_t< MyConstant >::least would give the type you are looking for.

只有影子陪我不离不弃 2024-10-03 17:08:52

您可以使用以下代码。它仅适用于 8/16/32/64 位正整数。但您也可以对负值进行适当的更改。

template <typename T, T x> class TypeFor
{
    template <T x>
    struct BitsRequired {
        static const size_t Value = 1 + BitsRequired<x/2>::Value;
    };
    template <>
    struct BitsRequired<0> {
        static const size_t Value = 0;
    };


    static const size_t Bits = BitsRequired<x>::Value;
    static const size_t Bytes = (Bits + 7) / 8;

    static const size_t Complexity = 1 + BitsRequired<Bytes-1>::Value;

    template <size_t c> struct Internal {
    };

    template <> struct Internal<1> {
        typedef UCHAR Type;
    };
    template <> struct Internal<2> {
        typedef USHORT Type;
    };
    template <> struct Internal<3> {
        typedef ULONG Type;
    };
    template <> struct Internal<4> {
        typedef ULONGLONG Type;
    };

public:

    typedef typename Internal<Complexity>::Type Type;

};


TypeFor<UINT, 117>::Type x;

PS 这在 MSVC 下编译。可能需要进行一些调整才能将其应用于 gcc/mingw/等。

You may use the following code. It works only for positive 8/16/32/64bit integers. But you may do the appropriate changes for negative values as well.

template <typename T, T x> class TypeFor
{
    template <T x>
    struct BitsRequired {
        static const size_t Value = 1 + BitsRequired<x/2>::Value;
    };
    template <>
    struct BitsRequired<0> {
        static const size_t Value = 0;
    };


    static const size_t Bits = BitsRequired<x>::Value;
    static const size_t Bytes = (Bits + 7) / 8;

    static const size_t Complexity = 1 + BitsRequired<Bytes-1>::Value;

    template <size_t c> struct Internal {
    };

    template <> struct Internal<1> {
        typedef UCHAR Type;
    };
    template <> struct Internal<2> {
        typedef USHORT Type;
    };
    template <> struct Internal<3> {
        typedef ULONG Type;
    };
    template <> struct Internal<4> {
        typedef ULONGLONG Type;
    };

public:

    typedef typename Internal<Complexity>::Type Type;

};


TypeFor<UINT, 117>::Type x;

P.S. this compiles under MSVC. Probably some adjustment should be done to adopt it for gcc/mingw/etc.

笔落惊风雨 2024-10-03 17:08:52

如何避免这个问题:

BOOST_STATIC_ASSERT((1LL << (8*sizeof(T))) >= number);

How about you avoid the problem:

BOOST_STATIC_ASSERT((1LL << (8*sizeof(T))) >= number);
怪我太投入 2024-10-03 17:08:52

BOOST_STATIC_ASSERT(int(60000)==60000) 怎么样?这将测试 60000 是否适合 int。如果 int 为 16 位,则 int(60000)27232。为了进行比较,这将被零扩展回 32 位长,并且可靠地失败。

How about BOOST_STATIC_ASSERT(int(60000)==60000) ? This will test whether 60000 fits in an int. If int is 16 bits, int(60000) is 27232. For the comparison, this will then be zero-extended back to a 32 bits long, and fail reliably.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文