使用固定大小类型时强制位字段的符号(前C ++ 14)

问题描述 投票:2回答:2

跳到粗体部分的基本问题,其余的只是背景。

由于我不想进入的原因,我正在编写一个代码生成器,它在(非常)预C ++ 14环境中生成C ++结构。生成器必须创建位域;它还需要以尽可能便携的方式尽可能地控制所生成字段的行为。我需要控制底层分配单元的大小,以及如何处理签名值。我不会理解为什么我这么愚蠢的事情,这显然违反了实施定义的行为,但是涉及薪水,所有正确的方法去做需要做的事情都遭到了人们的拒绝谁安排薪水。

所以我不知道如下:

int32_t x : 11;

因为我需要说服编译器该字段(以及具有相同底层类型的其他相邻字段)存在于32位字中。为底层类型生成int不是一个选项,因为int没有固定的大小,并且当有人发布int为64位宽的编译器时,事情会非常错误,或者我们最终返回到它的16位。

在pre-C ++ 14中,int x: 11可能是也可能不是无符号字段,并且您可以在显式signedunsigned之前添加所需内容。我担心int32_t和朋友会有同样的歧义(为什么不呢?)但是编译器在signed int32_t上呕吐。

C ++标准是否对intxx_t类型是否在位字段上强制签名有任何说法?如果没有,是否有任何保证

typedef signed int I32;
...
I32 x : 11;
...
assert(sizeof(I32)==4); //when this breaks, you won't have fun

将带签名的指标带入位域?

请注意,任何以“只生成一个函数...”开头的建议都是通过表格中的命令。这些生成的头文件将被插入到执行s-> x = 17之类的代码中;而且我已经很好地向我解释说,我不能建议将它全部更改为s->set_x(17)甚至一次。即使我可以简单地生成一个set_x函数来完全和安全地执行我需要的任何实现定义的行为。此外,我非常清楚位字段的变幻莫测,左右和左右内外以及其他任何编译器与它们相关的内容,以及其他几个原因,这就是为什么这是一个傻瓜的差事。而且我不能只是“尝试一下”,因为这需要在我没有的编译器上工作,这就是为什么我在标准中的保证之后争先恐后。

注意:我无法实现任何不允许现有代码简单地将指向字节缓冲区的指针强制转换为指向生成的struct的指针的解决方案,然后使用它们的指针来获取要读取和写入的字段。现有代码都是关于s-> x的,并且必须不进行任何更改。这排除了生成代码中涉及构造函数的任何解决方案。

c++ language-lawyer bit-fields
2个回答
1
投票

C ++标准是否对intxx_t类型是否在位字段上强制签名有任何说法?

没有。


标准的<cstdint>[cstdint.syn]的固定宽度整数的概要(链接到现代标准;概要的相关部分在the C++11 standard中看起来相同)只是描述(不是通过signed / unsigned关键字),它们应该是“有符号整数类型”或“无符号整数类型”。

例如。 for gcc<cstdint>暴露the fixed width integers of <stdint.h>,而__INT32_TYPE__又是预定义的预处理器宏的类型定义(例如int32_t用于signed),后者是特定于平台的。

该标准并未强制要求在此概要中使用unsignedCWG 739关键字,因此在C ++ 11中,固定宽度整数类型的位字段在声明时会遇到与其签名相同的实现定义行为。一个普通的整数位字段。回想一下,在C ++ 14之前[class.bit] / 3的相关部分是(由于char而采取行动之前):

它是实现定义的是一个普通(既不是明确签名也不是无符号)shortintlonglong longHow are the GNU C preprocessor predefined macros used?位字段是有符号还是无符号。 ...

确实,以下线程

  • __INT32_TYPE__

表示一个例子,例如在回答者的特定平台上的signed被定义为没有明确存在$ gcc -dM -E - < /dev/null | grep __INT ... #define __INT32_TYPE__ int 关键字:

struct

0
投票

它还需要以尽可能便携的方式尽可能地控制所生成字段的行为。我需要控制底层分配单元的大小,以及如何处理签名值。

这两个目标是不相容的。 Bitfields固有地存在可移植性问题。

如果标准定义了你想要的行为,那么“变位字段的变形”将不存在,并且人们不会打扰推荐使用位掩码和移位来实现可移植性。

您可能要做的是提供一个类,该类暴露与具有位域的class BitfieldProxy { public: BitfieldProxy(uint32_t& u) : x((u >> 4) & 0x7FF), y(u & 0xF), mDest(u) { } ~BitfieldProxy() { assert((x & 0x7FF) == x); assert((y & 0xF) == y); dest = (x << 4) | y; } BitfieldProxy(const BitfieldProxy&) = delete; BitfieldProxy& operator=(const BitfieldProxy&) = delete; // Only the last 11 bits are valid. unsigned int x; // Only the last 4 bits are valid. unsigned int y; private: uint32_t& mDest; }; 相同的接口,但实际上并不在内部使用位域。然后你可以让它的构造函数和析构函数通过掩码和移位来读取或写入这些字段。例如,类似于:

qazxswpoi
© www.soinside.com 2019 - 2024. All rights reserved.