Sun Studio 12:C 用户指南

5.4 内存引用约束的示例

节提供的代码示例很可能出现在您的源文件中。每个示例后跟对编译器代码假定的讨论,这些假定取决于所应用的基于类型的分析级别。

考虑以下代码。可以使用不同的别名级别对它进行编译,以说明显示类型的别名关系。

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 选项编译5.4 内存引用约束的示例,则编译器将认为以下间接访问互为别名:

*ip*sp*fp*bpfp->f1fp->f2fp->f3fp->f4bp->b1bp->b2bp->b3

如果使用 -xalias_level=basic 选项编译5.4 内存引用约束的示例,则编译器将认为以下间接访问互为别名:

*ip*bpfp->f1fp->f4bp->b1bp->b2bp->b3

另外,*spfp->f2fp->f3 可以互为别名,*sp*fp 可以互为别名。

但是,在 -xalias_level=basic 条件下,编译器作出以下假定:

由于两个间接访问的访问类型是不同的基本类型,因此编译器作出这些假定。

如果使用 -xalias_level=weak 选项编译5.4 内存引用约束的示例,则编译器假定以下别名信息:

由于 f1 是结构中偏移为 0 的字段,而 b2 是结构中偏移为 4 个字节的字段,因此编译器假定 fp->fp1 不将 bp->b2 作为别名。同样,编译器假定 fp->f1 不将 bp->b3 作为别名,fp->f4 不将 bp->b1bp->b2 作为别名。

如果使用 -xalias_level=layout 选项编译5.4 内存引用约束的示例,则编译器假定以下信息:

由于 f4b3 不是 foobar 的公共初始序列中的对应字段,因此 fp->f4 不将 bp->b3 作为别名。

如果使用 -xalias_level=strict 选项编译5.4 内存引用约束的示例,则编译器假定以下别名信息:

如果 -xalias_level=strict,则编译器假定 *fp*bpfp->f1fp->f2fp->f3fp->f4bp->b1bp->b2bp->b3 不互为别名,因为在忽略字段名时 foobar 是不同的。但是,fp 可将 fp->f1 作为别名,bp 可将 bp->b1 作为别名。

如果使用 -xalias_level=std 选项编译5.4 内存引用约束的示例,则编译器假定以下别名信息:

但是,fp->f1 不将 bp->b1bp->b2bp->b3 作为别名,因为在考虑字段名时 foobar 并不相同。

如果使用 -xalias_level=strong 选项编译5.4 内存引用约束的示例,则编译器假定以下别名信息:

考虑以下源代码示例。当使用不同的别名级别编译时,它说明显示的类型的别名关系。

struct foo {
    int f1;
    int f2;
    int f3;
} *fp;

struct bar {
    int b1;
    int b2;
    int b3;
} *bp;

如果使用 -xalias_level=any 选项编译5.4 内存引用约束的示例,则编译器假定以下别名信息:

*fp*bpfp->f1fp->f2fp->f3bp->b1bp->b2bp->b3 都可以互为别名,因为任何两个内存访问在 -xalias_level=any 级别上可互为别名。

如果使用 -xalias_level=basic 选项编译5.4 内存引用约束的示例,则编译器假定以下别名信息:

*fp*bpfp->f1fp->f2fp->f3bp->b1bp->b2bp->b3 都可以互为别名。在本示例中,由于所有结构字段均为同一基本类型,因此任何两个使用指针 *fp*bp 的字段访问都可以互为别名。

如果使用 -xalias_level=weak 选项编译5.4 内存引用约束的示例,则编译器假定以下别名信息:

但是,-xalias_level=weak 强加以下限制:

如果使用 -xalias_level=layout 选项编译5.4 内存引用约束的示例,则编译器假定以下别名信息:

但是,-xalias_level=layout 强加以下限制:

如果使用 -xalias_level=strict 选项编译5.4 内存引用约束的示例,则编译器假定以下别名信息:

但是,-xalias_level=strict 强加以下限制:

如果使用 -xalias_level=std 选项编译5.4 内存引用约束的示例,则编译器假定以下别名信息:

fp->f1fp->f2fp->f3bp->b1bp->b2bp->b3 不互为别名。

如果使用 -xalias_level=strong 选项编译5.4 内存引用约束的示例,则编译器假定以下别名信息:

fp->f1fp->f2fp->f3bp->b1bp->b2bp->b3 不互为别名。

考虑下列源代码示例,它说明某些别名级别无法处理内部指针。有关内部指针的定义,请参见表 B–11

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);

weaklayoutstrictstd 不支持5.4 内存引用约束的示例中的解除引用。在指针赋值 bp=(struct bar*)(&fp->f2) 之后,以下各对内存访问将访问相同的存储单元:

但是,使用选项 weaklayoutstrictstd 时,编译器假定 fp->f2bp->b2 不设定别名。由于 b2 的偏移为零,与 f2 的偏移(四字节)不同,并且 foobar 没有公共初始序列,因此编译器作出该假定。同样,编译器还假定 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 是表达式 fp->fb.b2 的另一种形式。由于 fp->fbbar 类型,因此 fp->f2 访问 barb2 字段。此外,bp->b2 也访问 barb2 字段。因此,编译器假定 fp->f2bp->b2 作为别名。同样,编译器假定 fp->f3bp->b3 作为别名,fp->f4bp->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 选项编译5.4 内存引用约束的示例,则编译器假定以下别名信息:

fp->f2 可将 cp->c2 作为别名,因为 *dp 可将 *cp 作为别名,且 *fp 可将 dp->db 作为别名。

cp->cf.f1 不将 dp->db.b1 作为别名。

cp->c2 不将 dp->db.b1 作为别名,cp->c2 不将 dp->d3 作为别名。

对于偏移,仅当 *dpcp->cf 作为别名时,cp->c2 才能将 db->db.b1 作为别名。但是,如果 *dpcp->cf 作为别名,则 dp->db.b1 必须在 foo cf 末尾之后设定别名,这是对象约束所禁止的。因此,编译器假定 cp->c2 不能将 db->db.b1 作为别名。

cp->c3 可将 dp->d3 作为别名。

请注意,cp->c3 不将 dp->db.b2 作为别名。由于具有非关联化所涉及的类型的字段的偏移不同并且不重叠,因此这些内存引用不设定别名。基于这种情况,编译器假定它们不能设定别名。

请注意,dp->d3 不将 cp->cf.f2 作为别名。由于具有非关联化所涉及的类型的字段的偏移不同并且不重叠,因此这些内存引用不设定别名。基于这种情况,编译器假定它们不能设定别名。

如果使用 -xalias_level=layout 选项编译5.4 内存引用约束的示例,则编译器仅假定以下别名信息:

如果使用 -xalias_level=strict 选项编译5.4 内存引用约束的示例,则编译器仅假定以下别名信息:

如果使用 -xalias_level=std 选项编译5.4 内存引用约束的示例,则编译器仅假定以下别名信息:

考虑以下源代码示例。

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;

下面是编译器根据以下别名级别作出的假定:

考虑以下源代码示例。

struct bar;

struct foo {
        struct foo *ffp;
        struct bar *fbp;
} *fp;

struct bar {
        struct bar *bbp;
        long        b2;
} *bp;

下面是编译器根据以下别名级别作出的假定:

考虑以下源代码示例:

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 告知编译器,允许 foobar 互为别名。编译器作出关于别名信息的以下假定: