5.13.5.2.2.1.1.3.3. 浮点数
与形式多样的整形常量不同,在 C++ 的前端中,具有 REAL_TYPE 类型的常量只能是 REAL_CST 。
output_constant (continue)
3791 case REAL_TYPE:
3792 if (TREE_CODE (exp) != REAL_CST)
3793 error ("initializer for floating value is not a floating constant");
3794
3795 assemble_real (TREE_REAL_CST (exp), TYPE_MODE (TREE_TYPE (exp)), align);
3796 break ;
有关浮点常量的内容,在 创建浮点常量节点 一节已经有详细的描述,这里不再重复。
1918 void
1919 assemble_real (REAL_VALUE_TYPE d, enum machine_mode mode, unsigned int align)
1920 {
1921 long data[4];
1922 int i;
1923 int bitsize, nelts, nunits, units_per;
1924
1925 /* This is hairy. We have a quantity of known size. real_to_target
1926 will put it into an array of *host* longs, 32 bits per element
1927 (even if long is more than 32 bits). We need to determine the
1928 number of array elements that are occupied (nelts) and the number
1929 of *target* min-addressable units that will be occupied in the
1930 object file (nunits). We cannot assume that 32 divides the
1931 mode's bitsize (size * BITS_PER_UNIT) evenly.
1932
1933 size * BITS_PER_UNIT is used here to make sure that padding bits
1934 (which might appear at either end of the value; real_to_target
1935 will include the padding bits in its output array) are included. */
1936
1937 nunits = GET_MODE_SIZE (mode);
1938 bitsize = nunits * BITS_PER_UNIT;
1939 nelts = CEIL (bitsize, 32);
1940 units_per = 32 / BITS_PER_UNIT;
1941
1942 real_to_target (data, &d, mode);
1943
1944 /* Put out the first word with the specified alignment. */
1945 assemble_integer (GEN_INT (data[0]), MIN (nunits, units_per), align, 1);
1946 nunits -= units_per;
1947
1948 /* Subsequent words need only 32-bit alignment. */
1949 align = min_align (align, 32);
1950
1951 for (i = 1; i < nelts; i++)
1952 {
1953 assemble_integer (GEN_INT (data[i]), MIN (nunits, units_per), align, 1);
1954 nunits -= units_per;
1955 }
1956 }
上面 1942 行的 real_to_target 的核心是 round_for_format 函数,及与目标机器关联的 real_format 结构中的格式编码函数(通常是 encode_ieee_single 或 encode_ieee_double )。
5.13.5.2.2.1.1.3.4. 字符串
字符串,在 C/C++ 中,默认就被视为常量。其对应的节点是 STRING_CST 。
output_constant (continue)
3798 case COMPLEX_TYPE:
3799 output_constant (TREE_REALPART (exp), thissize / 2, align);
3800 output_constant (TREE_IMAGPART (exp), thissize / 2,
3801 min_align (align, BITS_PER_UNIT * (thissize / 2)));
3802 break ;
3803
3804 case ARRAY_TYPE:
3805 case VECTOR_TYPE:
3806 if (TREE_CODE (exp) == CONSTRUCTOR)
3807 {
3808 output_constructor (exp, size, align);
3809 return ;
3810 }
3811 else if (TREE_CODE (exp) == STRING_CST)
3812 {
3813 thissize = MIN ((unsigned HOST_WIDE_INT)TREE_STRING_LENGTH (exp),
3814 size);
3815 assemble_string (TREE_STRING_POINTER (exp), thissize);
3816 }
3817 else if (TREE_CODE (exp) == VECTOR_CST)
3818 {
3819 int elt_size;
3820 tree link;
3821 unsigned int nalign;
3822 enum machine_mode inner;
3823
3824 inner = GET_MODE_INNER (TYPE_MODE (TREE_TYPE (exp)));
3825 nalign = MIN (align, GET_MODE_ALIGNMENT (inner));
3826
3827 elt_size = GET_MODE_UNIT_SIZE (TYPE_MODE (TREE_TYPE (exp)));
3828
3829 link = TREE_VECTOR_CST_ELTS (exp);
3830 output_constant (TREE_VALUE (link), elt_size, align);
3831 while ((link = TREE_CHAIN (link)) != NULL)
3832 output_constant (TREE_VALUE (link), elt_size, nalign);
3833 }
3834 else
3835 abort ();
3836 break ;
STRING_CST 只是简单地封装了字符串,通过 TREE_STRING_POINTER 及 TREE_STRING_LENGTH 可以获得这个字符串及其长度。
1190 void
1191 assemble_string (const char *p, int size) in varasm.c
1192 {
1193 int pos = 0;
1194 int maximum = 2000;
1195
1196 /* If the string is very long, split it up. */
1197
1198 while (pos < size)
1199 {
1200 int thissize = size - pos;
1201 if (thissize > maximum)
1202 thissize = maximum;
1203
1204 ASM_OUTPUT_ASCII (asm_out_file , p, thissize);
1205
1206 pos += thissize;
1207 p += thissize;
1208 }
1209 }
为了避免汇编代码中对段长度的限制,每块字符串长度不超过 2000 个字符。下面的宏输出字符串的内容。在 452 行, STRING_LIMIT 被定义为 256 。也就是说如果字符串(剩下)部分少于 256 个字符,就通过 ASM_OUTPUT_LIMITED_STRING 来输出,这个宏与这里的 ASM_OUTPUT_ASCII 很类似。在 445 及 456 行,输出的是字符“ ” ”并换行。可以想见,这个宏将输出形如:
“………”
“………”
的字符串。
430 #undef ASM_OUTPUT_ASCII
431 #define ASM_OUTPUT_ASCII (FILE, STR, LENGTH) / in elfos.h
432 do /
433 { /
434 register const unsigned char *_ascii_bytes = /
435 (const unsigned char *) (STR); /
436 register const unsigned char *limit = _ascii_bytes + (LENGTH); /
437 register unsigned bytes_in_chunk = 0; /
438 /
439 for (; _ascii_bytes < limit; _ascii_bytes++) /
440 { /
441 register const unsigned char *p; /
442 /
443 if (bytes_in_chunk >= 60) /
444 { /
445 fprintf ((FILE), "/"/n"); /
446 bytes_in_chunk = 0; /
447 } /
448 /
449 for (p = _ascii_bytes; p < limit && *p != '/0'; p++) /
450 continue ; /
451 /
452 if (p < limit && (p - _ascii_bytes) <= (long)STRING_LIMIT) /
453 { /
454 if (bytes_in_chunk > 0) /
455 { /
456 fprintf ((FILE), "/"/n"); /
457 bytes_in_chunk = 0; /
458 } /
459 /
460 ASM_OUTPUT_LIMITED_STRING ((FILE), _ascii_bytes); /
461 _ascii_bytes = p; /
462 } /
463 else /
464 { /
465 register int escape; /
466 register unsigned ch; /
467 /
468 if (bytes_in_chunk == 0) /
469 fprintf ((FILE), "%s/"", ASCII_DATA_ASM_OP); /
470 /
471 switch (escape = ESCAPES[ch = *_ascii_bytes]) /
472 { /
473 case 0: /
474 putc (ch, (FILE)); /
475 bytes_in_chunk++; /
476 break ; /
477 case 1: /
478 fprintf ((FILE), "//%03o", ch); /
479 bytes_in_chunk += 4; /
480 break ; /
481 default : /
482 putc ('//', (FILE)); /
483 putc (escape, (FILE)); /
484 bytes_in_chunk += 2; /
485 break ; /
486 } /
487 } /
488 } /
489 /
490 if (bytes_in_chunk > 0) /
491 fprintf ((FILE), "/"/n"); /
492 } /
493 while (0)
在 469 行, ASCII_DATA_ASM_OP 被定义为“ /t.ascii/t ”。 471 行的 ESCAPES 是一个如下的字符串。
"/1/1/1/1/1/1/1/1btn/1fr/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/
/0/0/"/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/
/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0///0/0/0/
/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/1/
/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/
/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/
/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/
/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1"
它指定了如何输出对应的 ASCII 码的字母。
5.13.5.2.2.1.1.3.5. 聚集类初始值
如果聚集类型的存在初始值常量(初始值为空的情形由 output_constant 的 3756 行处理,参见 全 0的内容 一节),则来到下面的代码中。
output_constant (continue)
3838 case RECORD_TYPE:
3839 case UNION_TYPE:
3840 if (TREE_CODE (exp) == CONSTRUCTOR)
3841 output_constructor (exp, size, align);
3842 else
3843 abort ();
3844 return ;
3845
3846 case SET_TYPE:
3847 if (TREE_CODE (exp) == INTEGER_CST)
3848 assemble_integer (expand_expr (exp, NULL_RTX,
3849 VOIDmode, EXPAND_INITIALIZER),
3850 thissize, align, 1);
3851 else if (TREE_CODE (exp) == CONSTRUCTOR)
3852 {
3853 unsigned char *buffer = alloca (thissize);
3854 if (get_set_constructor_bytes (exp, buffer, thissize))
3855 abort ();
3856 assemble_string ((char *) buffer, thissize);
3857 }
3858 else
3859 error ("unknown set constructor type");
3860 return ;
3861
3862 case ERROR_MARK:
3863 return ;
3864
3865 default :
3866 abort ();
3867 }
3868
3869 if (size > thissize)
3870 assemble_zeros (size - thissize);
3871 }
前面我们看到 CONSTRUCTOR 节点在其 CONSTRUCTOR_ELTS 处保存了对应每个成员的初始值的 tree_list 链表。在这个链表的每个节点中,其 TREE_VALUE 域是初始值,其 TREE_PURPOSE 域,对于类类型是 FIELD_DECL 节点,对于数组类型则是索引。
3918 static void
3919 output_constructor (tree exp, unsigned HOST_WIDE_INT size, in varasm.c
3920 unsigned int align)
3921 {
3922 tree type = TREE_TYPE (exp);
3923 tree link, field = 0;
3924 tree min_index = 0;
3925 /* Number of bytes output or skipped so far.
3926 I n other words, current position within the constructor. */
3927 HOST_WIDE_INT total_bytes = 0;
3928 /* Nonzero means BYTE contains part of a byte, to be output. */
3929 int byte_buffer_in_use = 0;
3930 int byte = 0;
3931
3932 if (HOST_BITS_PER_WIDE_INT < BITS_PER_UNIT)
3933 abort ();
3934
3935 if (TREE_CODE (type) == RECORD_TYPE)
3936 field = TYPE_FIELDS (type);
3937
3938 if (TREE_CODE (type) == ARRAY_TYPE
3939 && TYPE_DOMAIN (type) != 0)
3940 min_index = TYPE_MIN_VALUE (TYPE_DOMAIN (type));
3941
3942 /* As LINK goes through the elements of the constant,
3943 FIELD goes through the structure fields, if the constant is a structure.
3944 if the constant is a union, then we override this,
3945 by getting the field from the TREE_LIST element.
3946 But the constant could also be an array. Then FIELD is zero.
3947
3948 There is always a maximum of one element in the chain LINK for unions
3949 (even if the initializer in a source program incorrectly contains
3950 more one). */
3951 for (link = CONSTRUCTOR_ELTS (exp);
3952 link;
3953 link = TREE_CHAIN (link),
3954 field = field ? TREE_CHAIN (field) : 0)
3955 {
3956 tree val = TREE_VALUE (link);
3957 tree index = 0;
3958
3959 /* The element in a union constructor specifies the proper field
3960 or index. */
3961 if ((TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE
3962 || TREE_CODE (type) == QUAL_UNION_TYPE)
3963 && TREE_PURPOSE (link) != 0)
3964 field = TREE_PURPOSE (link);
3965
3966 else if (TREE_CODE (type) == ARRAY_TYPE)
3967 index = TREE_PURPOSE (link);
3968
3969 #ifdef ASM_COMMENT_START
3970 if (field && flag_verbose_asm )
3971 fprintf (asm_out_file , "%s %s:/n",
3972 ASM_COMMENT_START,
3973 DECL_NAME (field)
3974 ? IDENTIFIER_POINTER (DECL_NAME (field))
3975 : "<anonymous>");
3976 #endif
3977
3978 /* Eliminate the marker that makes a cast not be an lvalue. */
3979 if (val != 0)
3980 STRIP_NOPS (val);
注意在上面对于数组,变量 field 是 NULL ,它使用变量 index ;对于类类型则反之。在 3980 行, STRIP_NOPS 将不影响汇编输出的封装(例如不需要产生代码的转换)去掉。
output_constructor (continue)
3982 if (index && TREE_CODE (index) == RANGE_EXPR)
3983 {
3984 unsigned HOST_WIDE_INT fieldsize
3985 = int_size_in_bytes (TREE_TYPE (type));
3986 HOST_WIDE_INT lo_index = tree_low_cst (TREE_OPERAND (index, 0), 0);
3987 HOST_WIDE_INT hi_index = tree_low_cst (TREE_OPERAND (index, 1), 0);
3988 HOST_WIDE_INT index;
3989 unsigned int align2 = min_align (align, fieldsize * BITS_PER_UNIT);
3990
3991 for (index = lo_index; index <= hi_index; index++)
3992 {
3993 /* Output the element's initial value. */
3994 if (val == 0)
3995 assemble_zeros (fieldsize);
3996 else
3997 output_constant (val, fieldsize, align2);
3998
3999 /* Count its size. */
4000 total_bytes += fieldsize;
4001 }
4002 }
前端的节点 RANGE_EXPR 用于数组,表示一个范围的元素。例如,
int a [8] = {0};
其初始值就是一个 RANGE_EXPR ,表示在索引 0 到 7 的范围内使用初始值 0 。在上面的代码中可用看到,其第一个操作数是下限,而第二个操作数则是上限。在 C++ 中, RANGE_EXPR 的初始值只可能是 0 。
满足下面 4003 行条件的节点是:数组( field 为 NULL )、非位域的类成员。变量 pos 保存了初始值所应用的位置。对于类成员,由于已经完成布局, 4010 行的 int_byte_position 通过调用 byte_position 获得其相对类头的偏移。对于数组,元素大小 x 索引跨度,就可以得到其到数组头的偏移( 4014 行)。
output_constructor (continue)
4003 else if (field == 0 || !DECL_BIT_FIELD (field))
4004 {
4005 /* An element that is not a bit-field. */
4006
4007 unsigned HOST_WIDE_INT fieldsize;
4008 /* Since this structure is static,
4009 we know the positions are constant. */
4010 HOST_WIDE_INT pos = field ? int_byte_position (field) : 0;
4011 unsigned int align2;
4012
4013 if (index != 0)
4014 pos = (tree_low_cst (TYPE_SIZE_UNIT (TREE_TYPE (val)), 1)
4015 * (tree_low_cst (index, 0) - tree_low_cst (min_index, 0)));
4016
4017 /* Output any buffered-up bit-fields preceding this element. */
4018 if (byte_buffer_in_use)
4019 {
4020 assemble_integer (GEN_INT (byte), 1, BITS_PER_UNIT, 1);
4021 total_bytes++;
4022 byte_buffer_in_use = 0;
4023 }
4024
4025 /* Advance to offset of this element.
4026 Note no alignment needed in an array, since that is guaranteed
4027 if each element has the proper size. */
4028 if ((field != 0 || index != 0) && pos != total_bytes)
4029 {
4030 assemble_zeros (pos - total_bytes);
4031 total_bytes = pos;
4032 }
4033
4034 /* Find the alignment of this element. */
4035 align2 = min_align (align, BITS_PER_UNIT * pos);
4036
4037 /* Determine size this element should occupy. */
4038 if (field)
4039 {
4040 fieldsize = 0;
4041
4042 /* If this is an array with an unspecified upper bound,
4043 the initializer determines the size. */
4044 /* ??? This ought to only checked if DECL_SIZE_UNIT is NULL,
4045 but we cannot do this until the deprecated support for
4046 initializing zero-length array members is removed. */
4047 if (TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE
4048 && TYPE_DOMAIN (TREE_TYPE (field))
4049 && ! TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (field))))
4050 {
4051 fieldsize = array_size_for_constructor (val);
4052 /* Given a non-empty initialization, this field had
4053 better be last. */
4054 if (fieldsize != 0 && TREE_CHAIN (field) != NULL_TREE)
4055 abort ();
4056 }
4057 else if (DECL_SIZE_UNIT (field))
4058 {
4059 /* ??? This can't be right. If the decl size overflows
4060 a host integer we will silently emit no data. */
4061 if (host_integerp (DECL_SIZE_UNIT (field), 1))
4062 fieldsize = tree_low_cst (DECL_SIZE_UNIT (field), 1);
4063 }
4064 }
4065 else
4066 fieldsize = int_size_in_bytes (TREE_TYPE (type));
4067
4068 /* Output the element's initial value. */
4069 if (val == 0)
4070 assemble_zeros (fieldsize);
4071 else
4072 output_constant (val, fieldsize, align2);
4073
4074 /* Count its size. */
4075 total_bytes += fieldsize;
4076 }
变量 total_bytes 记录着已初始化的大小。对于类, C++ 要求按成员声明的次序初始化(前端在布局时亦按照声明次序),因此如果出现 pos 不等于 total_bytes 的情况,则表明 pos 与 total_bytes 之间是一个填充域。按标准要求,用 0 填充之。对于数组,因为元素大小一致,元素之间不需要填充域,若 pos 不等于 total_bytes ,则表明这部分元素的初始值没有给出,根据标准,需初始化为 0 。在 4018 行,变量 byte_buffer_in_use 来自下面位域初始值的处理。
那么下面的代码就是对类中位域成员初始值的处理。首先,其初始值必须是整型常量, 4077 行条件保证这一点。另外,位域与其之前的域之间亦可能有填充域,在 4098 行完成这个填充。
output_constructor (continue)
4077 else if (val != 0 && TREE_CODE (val) != INTEGER_CST)
4078 error ("invalid initial value for member `%s'",
4079 IDENTIFIER_POINTER (DECL_NAME (field)));
4080 else
4081 {
4082 /* Element that is a bit-field. */
4083
4084 HOST_WIDE_INT next_offset = int_bit_position (field);
4085 HOST_WIDE_INT end_offset
4086 = (next_offset + tree_low_cst (DECL_SIZE (field), 1));
4087
4088 if (val == 0)
4089 val = integer_zero_node;
4090
4091 /* If this field does not start in this (or, next) byte,
4092 skip some bytes. */
4093 if (next_offset / BITS_PER_UNIT != total_bytes)
4094 {
4095 /* Output remnant of any bit field in previous bytes. */
4096 if (byte_buffer_in_use)
4097 {
4098 assemble_integer (GEN_INT (byte), 1, BITS_PER_UNIT, 1);
4099 total_bytes++;
4100 byte_buffer_in_use = 0;
4101 }
4102
4103 /* If still not at proper byte, advance to there. */
4104 if (next_offset / BITS_PER_UNIT != total_bytes)
4105 {
4106 assemble_zeros (next_offset / BITS_PER_UNIT - total_bytes);
4107 total_bytes = next_offset / BITS_PER_UNIT;
4108 }
4109 }
4110
4111 if (! byte_buffer_in_use)
4112 byte = 0;
4113
4114 /* We must split the element into pieces that fall within
4115 separate bytes, and combine each byte with previous or
4116 following bit-fields. */
4117
4118 /* next_offset is the offset n fbits from the beginning of
4119 the structure to the next bit of this element to be processed.
4120 end_offset is the offset of the first bit past the end of
4121 this element. */
4122 while (next_offset < end_offset)
4123 {
4124 int this_time;
4125 int shift;
4126 HOST_WIDE_INT value;
4127 HOST_WIDE_INT next_byte = next_offset / BITS_PER_UNIT;
4128 HOST_WIDE_INT next_bit = next_offset % BITS_PER_UNIT;
4129
4130 /* Advance from byte to byte
4131 within this element when necessary. */
4132 while (next_byte != total_bytes)
4133 {
4134 assemble_integer (GEN_INT (byte), 1, BITS_PER_UNIT, 1);
4135 total_bytes++;
4136 byte = 0;
4137 }
4138
4139 /* Number of bits we can process at once
4140 (all part of the same byte). */
4141 this_time = MIN (end_offset - next_offset,
4142 BITS_PER_UNIT - next_bit);
4143 if (BYTES_BIG_ENDIAN)
4144 {
4145 /* On big-endian machine, take the most significant bits
4146 first (of the bits that are significant)
4147 and put them into bytes from the most significant end. */
4148 shift = end_offset - next_offset - this_time;
4149
4150 /* Don't try to take a bunch of bits that cross
4151 the word boundary in the INTEGER_CST. We can
4152 only select bits from the LOW or HIGH part
4153 not from both. */
4154 if (shift < HOST_BITS_PER_WIDE_INT
4155 && shift + this_time > HOST_BITS_PER_WIDE_INT)
4156 {
4157 this_time = shift + this_time - HOST_BITS_PER_WIDE_INT;
4158 shift = HOST_BITS_PER_WIDE_INT;
4159 }
4160
4161 /* Now get the bits from the appropriate constant word. */
4162 if (shift < HOST_BITS_PER_WIDE_INT)
4163 value = TREE_INT_CST_LOW (val);
4164 else if (shift < 2 * HOST_BITS_PER_WIDE_INT)
4165 {
4166 value = TREE_INT_CST_HIGH (val);
4167 shift -= HOST_BITS_PER_WIDE_INT;
4168 }
4169 else
4170 abort ();
4171
4172 /* Get the result. This works only when:
4173 1 <= this_time <= HOST_BITS_PER_WIDE_INT. */
4174 byte |= (((value >> shift)
4175 & (((HOST_WIDE_INT) 2 << (this_time - 1)) - 1))
4176 << (BITS_PER_UNIT - this_time - next_bit));
4177 }
4178 else
4179 {
4180 /* On little-endian machines,
4181 take first the least significant bits of the value
4182 and pack them starting at the least significant
4183 bits of the bytes. */
4184 shift = next_offset - int_bit_position (field);
4185
4186 /* Don't try to take a bunch of bits that cross
4187 the word boundary in the INTEGER_CST. We can
4188 only select bits from the LOW or HIGH part
4189 not from both. */
4190 if (shift < HOST_BITS_PER_WIDE_INT
4191 && shift + this_time > HOST_BITS_PER_WIDE_INT)
4192 this_time = (HOST_BITS_PER_WIDE_INT - shift);
4193
4194 /* Now get the bits from the appropriate constant word. */
4195 if (shift < HOST_BITS_PER_WIDE_INT)
4196 value = TREE_INT_CST_LOW (val);
4197 else if (shift < 2 * HOST_BITS_PER_WIDE_INT)
4198 {
4199 value = TREE_INT_CST_HIGH (val);
4200 shift -= HOST_BITS_PER_WIDE_INT;
4201 }
4202 else
4203 abort ();
4204
4205 /* Get the result. This works only when:
4206 1 <= this_time <= HOST_BITS_PER_WIDE_INT. */
4207 byte |= (((value >> shift)
4208 & (((HOST_WIDE_INT) 2 << (this_time - 1)) - 1))
4209 << next_bit);
4210 }
4211
4212 next_offset += this_time;
4213 byte_buffer_in_use = 1;
4214 }
4215 }
4216 }
4217
4218 if (byte_buffer_in_use)
4219 {
4220 assemble_integer (GEN_INT (byte), 1, BITS_PER_UNIT, 1);
4221 total_bytes++;
4222 }
4223
4224 if ((unsigned HOST_WIDE_INT)total_bytes < size)
4225 assemble_zeros (size - total_bytes);
4226 }
上面的变量 next_offset 是这个位域的偏移(单位是比特),变量 end_offset 则记录着这个位域所要占用的内存的末尾(注意这个占用的内存可能多于一个字节,因此需要 4122 行的 WHILE 循环)。记得在类布局中(参见 GCC默认布局下的位域 及 MS布局下的位域 一节)多个位域可能将共享同一块内存,因此我们只写入整字节的数据,还没占满整字节的数据保存在 byte 中,并由 byte_buffer_in_use 指示。又因为多个位域可以共享同一块内存,那么在写入它们共同形成的比特位图(也就是数值)时,就有“大小头”( big-endian , little-endian )的考量。比如:
char a:2;
char b:3;
char c:3;
如果除了 a 的初始值为 1 外,其他都是 0 ,那么在小头( little-endian )机器上,我们需要向这个字节写入 1 ,而在大头( big-endian )机器上,则是 128 。因此还要根据宏 BYTES_BIG_ENDIAN 的定义分别处理。对于 x86/Linux ,这个宏定义为 0 ,是小头机器。