本节提供可能出现在您的源文件中的代码示例。每个示例后跟对编译器代码假定的讨论,这些假定取决于所应用的基于类型的分析级别。
考虑以下代码。可以使用不同的别名级别对它进行编译,以说明显示类型的别名关系。
struct foo {
int f1;
short f2;
short f3;
int f4;
} *fp;
struct bar {
int b1;
int b2;
int b3;
} *bp;
int *ip;
short *sp;如果该示例是使用 -xalias_level=any 选项编译的,编译器将认为以下间接访问互为别名:
*ip、*sp、*fp、*bp、fp->f1、fp->f2、fp->f3、fp->f4、bp->b1、bp->b2、bp->b3
如果该示例是使用 -xalias_level=basic 选项编译的,编译器将认为以下间接访问互为别名:
*ip、*bp、fp->f1、fp->f4、bp->b1、bp->b2、bp->b3
另外,*sp、fp->f2 和 fp->f3 可以互为别名,*sp 和 *fp 可以互为别名。
但是,在 -xalias_level=basic 条件下,编译器作出以下假定:
*ip 不将 *sp 作为别名。
*ip 不将 fp->f2 和 fp->f3 作为别名。
*sp 不将 fp->f1、fp->f4、bp->b1、bp->b2和 bp->b3 作为别名。
由于两个间接访问的访问类型是不同的基本类型,因此编译器作出这些假定。
如果该示例是使用 -xalias_level=weak 选项编译的,编译器将假定以下别名信息:
*ip 可将 *fp、fp->f1、fp->f4、*bp、bp->b1、bp->b2 和 bp->b3 作为别名。
*sp 可将 *fp、fp->f2 和 fp->f3 作为别名。
fp->f1 可将 bp->b1 作为别名。
fp->f4 可将 bp->b3 作为别名。
由于 f1 是结构中偏移为 0 的字段,而 b2 是结构中偏移为 4 个字节的字段,因此编译器假定 fp->fp1 不将 bp->b2 作为别名。同样,编译器假定 fp->f1 不将 bp->b3 作为别名,fp->f4 不将 bp->b1 或 bp->b2 作为别名。
如果该示例是使用 -xalias_level=layout 选项编译的,编译器将假定以下别名信息:
*ip 可将 *fp、*bp、fp->f1、fp->f4、bp->b1、bp->b2 和 bp->b3 作为别名。
*sp 可将 *fp、fp->f2 和 fp->f3 作为别名。
fp->f1 可将 bp->b1 和 *bp 作为别名。
*fp 和 *bp 可以互为别名。
fp->f4 不将 bp->b3 作为别名,因为 f4 和 b3 不是 foo 和 bar 公共初始序列中的对应字段。
如果该示例是使用 -xalias_level=strict 选项编译的,编译器将假定以下别名信息:
*ip 可将 *fp、fp->f1、fp->f4、*bp、bp->b1、bp->b2 和 bp->b3 作为别名。
*sp 可将 *fp、fp->f2 和 fp->f3 作为别名。
使用 -xalias_level=strict 时,编译器假定 *fp、*bp、fp->f1、fp->f2、fp->f3、fp->f4、bp->b1、bp->b2 和 bp->b3 不互为别名,因为在忽略字段名时 foo 和 bar 是不同的。但是,fp 可将 fp->f1 作为别名,bp 可将 bp->b1 作为别名。
如果该示例是使用 -xalias_level=std 选项编译的,编译器将假定以下别名信息:
*ip 可将 *fp、fp->f1、fp->f4、*bp、bp->b1、bp->b2 和 bp->b3 作为别名。
*sp 可将 *fp、fp->f2 和 fp->f3 作为别名。
但是,fp->f1 不将 bp->b1、bp->b2 或 bp->b3 作为别名,因为在考虑字段名时 foo 和 bar 是不同的。
如果该示例是使用 -xalias_level=strong 选项编译的,编译器将假定以下别名信息:
*ip 不将 fp->f1、fp->f4、bp->b1、bp->b2 和 bp->b3 作为别名,因为 *ip 等指针不应指向结构内部。
同样,*sp 不将 fp->f1 或 fp->f3 作为别名。
因为类型不同,*ip 不将 *fp、*bp 和 *sp 作为别名。
因为类型不同,*sp 不将 *fp、*bp 和 *ip 作为别名。
考虑以下源代码示例。当使用不同的别名级别编译时,它说明显示的类型的别名关系。
struct foo {
int f1;
int f2;
int f3;
} *fp;
struct bar {
int b1;
int b2;
int b3;
} *bp;如果该示例是使用 -xalias_level=any 选项编译的,编译器将假定以下别名信息:
*fp、*bp、fp->f1、fp->f2、fp->f3、bp->b1、bp->b2 和 bp->b3 都可以互为别名,因为任何两个内存访问在 -xalias_level=any 级别上可互为别名。
如果该示例是使用 -xalias_level=basic 选项编译的,编译器将假定以下别名信息:
*fp、*bp、fp->f1、fp->f2、fp->f3、bp->b1、bp->b2 和 bp->b3 都可以互为别名。在本示例中,由于所有结构字段均为同一基本类型,因此任何两个使用指针 *fp 和 *bp 的字段访问都可以互为别名。
如果该示例是使用 -xalias_level=weak 选项编译的,编译器将假定以下别名信息:
*fp 和 *fp 可以互为别名。
fp->f1 可将 bp->b1、*bp 和 *fp 作为别名。
fp->f2 可将 bp->b2、*bp 和 *fp 作为别名。
fp->f3 可将 bp->b3、*bp 和 *fp 作为别名。
但是,-xalias_level=weak 强加以下限制:
fp->f1 不将 bp->b2 或 bp->b3 作为别名,因为 f1 的偏移为零,这不同于 b2 的偏移(四字节)和 b3 的偏移(八字节)。
fp->f2 不将 bp->b1 或 bp->b3 作为别名,因为 f2 的偏移为四字节,这不同于 b1 的偏移(零字节)和 b3 的偏移(八字节)。
fp->f3 不将 bp->b1 或 bp->b2 作为别名,因为 f3 的偏移为八字节,这不同于 b1 的偏移(零字节)和 b2 的偏移(四字节)。
如果该示例是使用 -xalias_level=layout 选项编译的,编译器将假定以下别名信息:
*fp 和 *bp 可以互为别名。
fp->f1 可将 bp->b1、*bp 和 *fp 作为别名。
fp->f2 可将 bp->b2、*bp 和 *fp 作为别名。
fp->f3 可将 bp->b3、*bp 和 *fp 作为别名。
但是,-xalias_level=layout 强加以下限制:
fp->f1 不将 bp->b2 或 bp->b3 作为别名,因为在 foo 和 bar 公共初始序列中,字段 f1 对应于字段 b1。
fp->f2 不将 bp->b1 或 bp->b3 作为别名,因为在 foo 和 bar 公共初始序列中,字段 f2 对应于字段 b2。
fp->f3 不将 bp->b1 或 bp->b2 作为别名,因为在 foo 和 bar 公共初始序列中,字段 f3 对应于字段 b3。
如果该示例是使用 -xalias_level=strict 选项编译的,编译器将假定以下别名信息:
*fp 和 *bp 可以互为别名。
fp->f1 可将 bp->b1、*bp 和 *fp 作为别名。
fp->f2 可将 bp->b2、*bp 和 *fp 作为别名。
fp->f3 可将 bp->b3、*bp 和 *fp 作为别名。
但是,-xalias_level=strict 强加以下限制:
fp->f1 不将 bp->b2 或 bp->b3 作为别名,因为在 foo 和 bar 公共初始序列中,字段 f1 对应于字段 b1。
fp->f2 不将 bp->b1 或 bp->b3 作为别名,因为在 foo 和 bar 公共初始序列中,字段 f2 对应于字段 b2。
fp->f3 不将 bp->b1 或 bp->b2 作为别名,因为在 foo 和 bar 公共初始序列中,字段 f3 对应于字段 b3。
如果该示例是使用 -xalias_level=std 选项编译的,编译器将假定以下别名信息:
fp->f1、fp->f2、fp->f3、bp->b1、bp->b2 和 bp->b3 不互为别名。
如果该示例是使用 -xalias_level=strong 选项编译的,编译器将假定以下别名信息:
fp->f1、fp->f2、fp->f3、bp->b1、bp->b2 和 bp->b3 不互为别名。
考虑下列源代码示例,它说明某些别名级别无法处理内部指针。有关内部指针的定义,请参见表 49。
struct foo {
int f1;
struct bar *f2;
struct bar *f3;
int f4;
int f5;
struct bar fb[10];
} *fp;
struct bar
struct bar *b2;
struct bar *b3;
int b4;
} *bp;
bp=(struct bar*)(&fp->f2);weak、layout、strict 或 std 不支持该示例中的非关联化。在指针赋值 bp=(struct bar*)(&fp->f2) 之后,以下各对内存访问会访问相同的内存位置:
fp->f2 和 bp->b2 会访问相同内存位置
fp->f3 和 bp->b3 会访问相同内存位置
fp->f4 和 bp->b4 会访问相同内存位置
但是,在使用 weak、layout、strict 和 std 选项时,编译器假定 fp->f2 和 bp->b2 不互为别名。由于 b2 的偏移为零,与 f2 的偏移(四字节)不同,并且 foo 和 bar 没有公共初始序列,因此编译器作出该假定。同样,编译器也假定 bp->b3 和 fp->f3 不互为别名,bp->b4 和 fp->f4 不互为别名。
因此,指针赋值 bp=(struct bar*)(&fp->f2) 将使编译器关于别名信息的假定不正确。此情况可能会导致不正确的优化。
请在进行以下示例中显示的修改之后尝试编译。
struct foo {
int f1;
struct bar fb; /* Modified line */
#define f2 fb.b2 /* Modified line */
#define f3 fb.b3 /* Modified line */
#define f4 fb.b4 /* Modified line */
int f5;
struct bar fb[10];
} *fp;
struct bar
struct bar *b2;
struct bar *b3;
int b4;
} *bp;
bp=(struct bar*)(&fp->f2);在指针赋值 bp=(struct bar*)(&fp->f2) 之后,以下各对内存访问会访问相同的内存位置:
fp->f2 和 bp->b2
fp->f3 和 bp->b3
fp->f4 和 bp->b4
此代码示例中显示的更改说明了表达式 fp->f2 是表达式 fp->fb.b2 的另一种形式。由于 fp->fb 的类型为 bar,因此fp->f2 会访问 bar 的 b2 字段。此外,bp->b2 也会访问 bar 的 b2 字段。因此,编译器假定 fp->f2 将 bp->b2 作为别名。同样,编译器也假定 fp->f3 将 bp->b3 作为别名,fp->f4 将 bp->b4 作为别名。结果,编译器假定的别名与指针赋值产生的实际别名匹配。
考虑以下源代码示例。
struct foo {
int f1;
int f2;
} *fp;
struct bar {
int b1;
int b2;
} *bp;
struct cat {
int c1;
struct foo cf;
int c2;
int c3;
} *cp;
struct dog {
int d1;
int d2;
struct bar db;
int d3;
} *dp;如果该示例是使用 -xalias_level=weak 选项编译的,编译器将假定以下别名信息:
fp->f1 可将 bp->b1、cp->c1、dp->d1、cp->cf.f1 和 df->db.b1 作为别名。
fp->f2 可将 bp->b2、cp->cf.f1、dp->d2、cp->cf.f2、df->db.b2、cp->c2 作为别名。
bp->b1 可将 fp->f1、cp->c1、dp->d1、cp->cf.f1 和 df->db.b1 作为别名。
bp->b2 可将 fp->f2、cp->cf.f1、dp->d2、cp->cf.f1 和 df->db.b2 作为别名。
fp->f2 可将 cp->c2 作为别名,因为*dp 可将 *cp 作为别名,*fp 可将 dp->db 作为别名。
cp->c1 可将 fp->f1、bp->b1、dp->d1 和 dp->db.b1 作为别名。
cp->cf.f1 可将 fp->f1、fp->f2、bp->b1、bp->b2、dp->d2 和 dp->d1 作为别名。
cp->cf.f1 不将 dp->db.b1 作为别名。
cp->cf.f2 可将 fp->f2、bp->b2、dp->db.b1 和 dp->d2 作为别名。
cp->c2 可将 dp->db.b2 作为别名。
cp->c2 不将 dp->db.b1 作为别名,cp->c2 不将 dp->d3 作为别名。
对于偏移,仅当 *dp 将 cp->cf 作为别名时,cp->c2 才可将 db->db.b1 作为别名。但是,如果 *dp 将 cp->cf 作为别名,则 dp->db.b1 必须在 foo cf 末尾之后设定别名,这是对象约束所禁止的。因此,编译器假定 cp->c2 不可将 db->db.b1 作为别名。
cp->c3 可将 dp->d3 作为别名。
请注意,cp->c3 不将 dp->db.b2 作为别名。由于具有非关联化所涉及的类型的字段的偏移不同并且不重叠,因此这些内存引用不设定别名。基于这种情况,编译器假定它们不能设定别名。
dp->d1 可将 fp->f1、bp->b1 和 cp->c1 作为别名。
dp->d2 可将 fp->f2、bp->b2 和 cp->cf.f1 作为别名。
dp->db.b1 可将 fp->f1、bp->b1 和 cp->c1 作为别名。
dp->db.b2 可将 fp->f2、bp->b2、cp->c2 和 cp->cf.f1 作为别名。
dp->d3 可将 cp->c3 作为别名。
请注意,dp->d3 不将 cp->cf.f2 作为别名。由于具有非关联化所涉及的类型的字段的偏移不同并且不重叠,因此这些内存引用不设定别名。基于此分析,编译器假定它们不能设定别名。
如果该示例是使用 -xalias_level=layout 选项编译的,编译器只假定以下别名信息:
fp->f1、bp->b1、cp->c1 和 dp->d1 都可以互为别名。
fp->f2、bp->b2 和 dp->d2 都可以互为别名。
fp->f1 可将 cp->cf.f1 和 dp->db.b1 作为别名。
bp->b1 可将 cp->cf.f1 和 dp->db.b1 作为别名。
fp->f2 可将 cp->cf.f2 和 dp->db.b2 作为别名。
bp->b2 可将 cp->cf.f2 和 dp->db.b2 作为别名。
如果该示例是使用 -xalias_level=strict 选项编译的,编译器只假定以下别名信息:
fp->f1 和 bp->b1 可以互为别名。
fp->f2 和 bp->b2 可以互为别名。
fp->f1 可将 cp->cf.f1 和 dp->db.b1 作为别名。
bp->b1 可将 cp->cf.f1 和 dp->db.b1 作为别名。
fp->f2 可将 cp->cf.f2 和 dp->db.b2 作为别名。
bp->b2 可将 cp->cf.f2 和 dp->db.b2 作为别名。
如果该示例是使用 -xalias_level=std 选项编译的,编译器只假定以下别名信息:
fp->f1 可将 cp->cf.f1 作为别名。
bp->b1 可将 dp->db.b1 作为别名。
fp->f2 可将 cp->cf.f2 作为别名。
bp->b2 可将 dp->db.b2 作为别名。
考虑以下源代码示例。
struct foo {
short f1;
short f2;
int f3;
} *fp;
struct bar {
int b1;
int b2;
} *bp;
union moo {
struct foo u_f;
struct bar u_b;
} u;下面是编译器根据各种别名级别作出的假定:
如果该示例是使用 -xalias_level=weak 选项编译的,fp->f3 和 bp->b2 可互为别名。
如果该示例是使用 -xalias_level=layout 选项编译的,没有字段可互为别名。
如果该示例是使用 -xalias_level=strict 选项编译的,fp->f3 和 bp->b2 可互为别名。
如果该示例是使用 -xalias_level=std 选项编译的,没有字段可互为别名。
考虑以下源代码示例。
struct bar;
struct foo {
struct foo *ffp;
struct bar *fbp;
} *fp;
struct bar {
struct bar *bbp;
long b2;
} *bp;下面是编译器根据各种别名级别作出的假定:
如果该示例是使用 -xalias_level=weak 选项编译的,只有 fp->ffp 和 bp->bbp 可互为别名。
如果该示例是使用 -xalias_level=layout 选项编译的,只有 fp->ffp 和 bp->bbp 可互为别名。
如果该示例是使用 -xalias_level=strict 选项编译的,则没有字段可以互为别名,因为即使删除两种 struct 类型的标记,两种 struct 类型仍不相同。
如果该示例是使用 -xalias_level=std 选项编译的,则没有字段可以互为别名,原因是两种类型和标记均不相同。
考虑以下源代码示例:
struct foo;
struct bar;
#pragma alias (struct foo, struct bar)
struct foo {
int f1;
int f2;
} *fp;
struct bar {
short b1;
short b2;
int b3;
} *bp;此示例中的 pragma 告知编译器,允许 foo 和 bar 互为别名。编译器作出关于别名信息的以下假定: