内表转换规则
内表只能被转换成其他内表,而不能转换成结构或基本类型。
一个内表能否转换成其他内表与内表中的现有数据行没有关系,而是看两个内表的行结构是否可转换。
只要类型行是可以转换的,则内表就可以转换
C语言中的结构对齐
C中结构的内存分配是这样的:编译器会按照成员列表的顺序(声明的顺序)一个接一个地给每个成员分配内存,只有当存储成员时需要满足正确的边界要求时,成员之间才可能出现用于填充的额外内存空间(被浪费掉了的),如下面图中的灰色地带:
#include <stddef.h>
typedefstruct ALIGN {
chara;
intb;
charc;
}ALIGN;
printf("%d", offsetof(struct ALIGN,a));//0
printf("%d", offsetof(struct ALIGN,b));//4
printf("%d", offsetof(struct ALIGN,c));//8
printf("%d", sizeof (struct ALIGN));//12
如果编译器有成员对齐这一要求时,会按照最长类型来分配每一个成员,如上面的a成员,在整型类型长度为4字节的机器上,由于a是一个字符型,虽然本身只需一个字节,但也为a分配了4个字节,这将浪费3个字节的空间,c也是一样,此时需要总共12个字节的空间。如果将短的类型放在一起,这将会节约空间(此时只需要8个字节的空间):
typedefstruct ALIGN {
intb;
chara;
charc;
}ALIGN;
printf("%d", offsetof(struct ALIGN,b));//0
printf("%d", offsetof(struct ALIGN,a));//4
printf("%d", offsetof(struct ALIGN,c));//5
printf("%d", sizeof (struct ALIGN));//8
下面与上面也是一样节约空间:
typedefstruct ALIGN {
chara;
char c;
int b;
}ALIGN;
printf("%d", offsetof(struct ALIGN,a));//0
printf("%d", offsetof(struct ALIGN,c));//1
printf("%d", offsetof(struct ALIGN,b));//4
printf("%d", sizeof (struct ALIGN));//8
sizeof操作符能够得出一个结构体的整体长度,包括因边界对齐而填充的那些字节,如果想得到每个成员偏离结构首的字节数,则可以使用offsetof宏。
按照成员所占空间大小降序排列结构成员的声明可以最大限度地减少结构存储中浪费的内存空间。sizeof返回的值包含了结构中浪费的内存空间。
ABAP结构体对齐
ABAP中与C中是一样的,当组件的成员为混合类型时,就会出现对齐要求,如:
DATA: BEGIN OF struc,
c,
x TYPE x,
END OF struc.
DATA: bits TYPE i,
descr_ref TYPE REF TO cl_abap_structdescr.
descr_ref ?= cl_abap_structdescr=>describe_by_data( struc ).
bits = descr_ref->length.
WRITE :/ 'struc : ' , bits , ' byte'.
struc : 4 byte
与C程序中的结构一样,以所占空间最大的成员单位进行对齐。下面结构就不存在对齐要求:
DATA: BEGIN OF struc,
x TYPE x,
x1 TYPE x,
x2 TYPE x,
END OF struc.
DATA: bits TYPE i,
descr_ref TYPE REF TO cl_abap_structdescr.
descr_ref ?= cl_abap_structdescr=>describe_by_data( struc ).
bits = descr_ref->length.
WRITE :/ 'struc : ' , bits , ' byte'.
struc : 3 byte
在两个结构体之间转换或赋值时需要考虑对齐问题。
结构体相互赋值转换规则
结构是否可转换(相互赋值)主要由结构的声明布局决定。
The Unicode fragment view splits the structure into fragments as follows:
某个结构将根据下面的规则分成多个Unicode段视图:
- X类型组件在一起连续声明时,会形成连续的X类型片段,中间不会出现对齐的gap,对齐只会发生在X段最后面(具体补多少,则根据结构体中类型最长的组件来决定)
- 类型C,N,D, and T这些类型在一起连续声明时,会形成连续的C类型片段,中间不会出现对齐的gap,对齐只会发生在C片段最后面(具体补多少,则根据结构体中类型最长的组件来决定)
- 其它类型的组件,如I、F、P、STRING、XSTRING、引用类型、内表——————每个组件都会形成独立的不同类型的连续片段。
Thus there are no alignment gaps within each fragment in the Unicode fragment view. In Unicode systems, the order and formation of fragments in operands is compared, to determine the convertibility of structures.
每一种fragment片断内部是连续,在其内部是不存在补齐的空白字节,但可能发生片断尾部。
两个结果是否可以转换,主要是看fragment片段的种类(X、C、I、F、P、STRING、XSTRING、引用类型、内表)、fragment布局顺序、以及每种fragment的长度要相同(或者fragment尾部所补对齐要相同——但如果某个结构是另一结构的子布局,最后一个fragment长度并不要求一样,只要类型一样即可)。
不同长度结构体赋值(指在布局相同的情况下)
如果将一个结构赋给一个短的结构,源结构将会被截。如果将一个结构赋给长的结构,末尾不足的地方字符类型使用空格填充(包括日期与NUM类型),数字类型会使用0来初始化。
DATA: BEGIN OF fs1,
int TYPE i VALUE 5,
pack TYPE p DECIMALS 2 VALUE '2.26',
text(10) TYPE c VALUE 'fine text',
float TYPE f VALUE '1.234e+05',
data TYPE d VALUE '19950916',
END OF fs1.
DATA: BEGIN OF fs2,
int TYPE i VALUE 3,
pack TYPE p DECIMALS 2 VALUE '72.34',
text(5) TYPE c VALUE 'hello',
END OF fs2.
WRITE: / fs1-int, fs1-pack, fs1-text, fs1-float, fs1-data.
WRITE: / fs2-int, fs2-pack, fs2-text.
MOVE fs1 TO fs2.
WRITE: / fs2-int, fs2-pack, fs2-text.
5 2.26 fine text 1.2340000000000000E+05 19950916
3 72.34 hello
5 2.26 fine
可相互转换结构
DATA: BEGIN OF struc1,
a(1) TYPE x,
b(1) TYPE x,
c(6) TYPE c,
f TYPE f ,
END OF struc1.
DATA: BEGIN OF struc2,
a(2) TYPE x,
b(2) TYPE c,
c(4) TYPE n,
f TYPE f ,
END OF struc2.
The Unicode fragment view of both structures is:
X(2)
C(6)
F(8)
struc1 can be assigned to struc2 in Unicode systems.
如果将struc2的a的长度修改为其他值,则不可转换,但如果在struc2的尾部,即f字段后面加上一个其他任何类型的字段,这两个结构都是可以相互赋值转换的
不可相互转换结构
DATA: BEGIN OF struc1,
a TYPE d,
b TYPE t,
c TYPE f,
d(2) TYPE x,
e(4) TYPE x,
f(8) TYPE c,
END OF struc1.
DATA: BEGIN OF struc2,
a TYPE d,
b TYPE t,
BEGIN OF struc3,
c TYPE f,
d(2) TYPE x,
END OF struc3,
e(4) TYPE x,
f(8) TYPE c,
END OF struc2.
DATA: len1 TYPE i,len2 TYPE i.
DESCRIBE FIELD struc1 LENGTH len1 IN BYTE MODE.
DESCRIBE FIELD struc2 LENGTH len2 IN BYTE MODE.
WRITE:/ len1,len2. "64 72
The Unicode fragment view of the two structures is:
struc1 struc2
C(14字符=28字节)后面补4字节 C(14字符=28字节)后面补4字节
F(8字节) F(8字节)
X(6字节)后面补2字节 X(2字节)后面补6字节
C(8字符=16字节) X(4字节)后面补4字节
C(8字符=16字节)
在内部嵌套结构struc3中发生了对齐(注:嵌套结构尾部与外部结构相邻字段即使类型相同,但他们形成的fragment片段是独立的,不会合并在一起,即这里的d与e两个字段),并在struc2与内部嵌套结构struc3之间(即d与e之间)填补了对齐空白,但这种对齐空白在struc1中没有发生;
如果去掉struc2的e与f,则这两个结构是可以转换的(因为此时struc2比struc1要短,并且此时struc2现有的fragment片段布局与struc1基本上一样——除最后不一样,但因struc2比struc1要短,所以可以忽略尾部对齐大小);
但如果只去掉struc2的e字段,还是不能相互转换,因为此时虽然长度一样,但布局还是不一样(struc2的d字段后面补了6字节对齐空白,而struc1的e字段后面只需补2字节的对齐空白————虽然此时形成 的X类型fragment片段总体长度都是8字节,但从布局上来看还是不一样的)
纵深结构体赋值转换
含有纵深类型的结构也是可以相互转换的,但结构中相邻同类型字段并不会合并为一个fragment,所以如果有纵深类型的组件的两个结构可转换时需要这两个结构中所声明的字段个数、类型、位置要完全一样(包括两个结构体的长度也要一样),否则也是不能转换的,如下面两个结构是可以相互转换:
DATA: BEGIN OF struc1,
a(1) TYPE c,
b(1) TYPE c,
s TYPE string,
END OF struc1.
DATA: BEGIN OF struc2,
a(1) TYPE c,
b(1) TYPE c,
s TYPE string VALUE 'string',
END OF struc2.
但下面两个结构是不能相互转换的:
DATA: BEGIN OF struc1,
a(1) TYPE c,
b(1) TYPE c,
s TYPE string,
END OF struc1.
DATA: BEGIN OF struc2,
a(2) TYPE c,
s TYPE string VALUE 'string',
END OF struc2.
MOVE-CORRESPONDING(结构体赋值)
MOVE-CORRESPONDING <struct1>TO<struct2>.
该语句将struct1中与struct2中名称相同的组件复制过去
使用MOVE或“=”进行结构体赋值时,不是按照对应的组件名来进行的,它只与声明的顺序与类型有关,如果类型不同会出错,可以进行赋值转换的需要满足结构体相互赋值转换规则(参考上面)