与有效类型规则混淆 [英] Confused by effective type rules

查看:82
本文介绍了与有效类型规则混淆的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我似乎再次缺少关于有效类型的困惑...代码中的注释本质上是我的问题,但这是我可以考虑在适当的上下文中问这个问题的唯一方法.

I seem to be missing a few pieces of the puzzle regarding effective type again... The comments in the code are essentially my question, but it's the only way I can think to ask this question with proper context.

#include <stdlib.h>
#include <string.h>

typedef struct foo {
    int n;
} Foo;

int main(void)
{
    // No effective type yet because there has been no write to the memory.
    Foo *f = malloc(sizeof(Foo));

    // Effective type of `f` is now `Foo *`, except I'm writing to
    // `f->n`, so shouldn't it be `int *`? Not sure what's going on here.
    f->n = 1;

    // No effective type yet because there has been no write to the memory.
    char *buf = malloc(sizeof(Foo));

    // Effective type of `buf` is `Foo *`, despite it being declared as
    // `char *`.
    // It's not safe to modify `buf` as a `char` array since the effective type
    // is not `char`, or am I missing something?
    memcpy(buf, f, sizeof(Foo));

    // The cast here is well defined because effective type of `buf` is
    // `Foo *` anyway, right?
    ((Foo *)buf)->n++;

    // I'm not even sure this is OK. The effective type of `buf` is `Foo *`,
    // right? Why wouldn't it be OK then?
    memcpy(f, buf, sizeof(Foo));

    // Safe if the last `memcpy` was safe.
    f->n++;

    // buf now points to invalid memory.
    free(buf);

    // Pointers with different declared types point to the same object,
    // but they have the same effective type that is not qualified by
    // `restrict`, so this doesn't violate strict aliasing, right?
    // This is allowed because `f` was allocated via `malloc`,
    // meaning it is suitably aligned for any data type, so
    // the effective type rules aren't violated either.
    buf = (void *)f;

    // `f`, and consequently `buf` since it points to the same object as `f`,
    // now point to invalid memory.
    free(f);
}

我是否认为所有这些都可以,还是在某些情况下我错了?我意识到这是一个界限,要问多个问题,但实际上是在问我对有效类型和严格别名的理解是否正确. GCC使用-pedantic-errors -Wextra -Wall -O2 -fstrict-aliasing -Wstrict-aliasing

Am I correct in thinking that all of that is OK, or am I wrong in some cases? I realize this is borderline asking multiple questions, but I'm essentially asking whether my understanding of effective type and strict aliasing is correct. GCC produced no diagnostics for me with -pedantic-errors -Wextra -Wall -O2 -fstrict-aliasing -Wstrict-aliasing

推荐答案

您似乎对适用于有效类型"的内容感到困惑:适用于已分配空间,而不适用于任何指针.与C语言一样,指针是一个单独的对象,具有指向该指针可能碰到的任何空间的独立属性.

You seem to be mixed up about what "effective type" applies to: it applies to the malloc'd space, not any pointer. As always in C, a pointer is a separate object with separate properties to any space that the pointer may happen to point to.

f是一个(命名的)变量,因此其有效类型始终与其声明的类型相同,即Foo *.同样,buf的有效类型始终为char *.有效类型只能在运行时更改的唯一时间是动态分配的空间.

f is a (named) variable so its effective type is always the same as its declared type, namely Foo *. Similarly buf's effective type is always char *. The only time that the effective type may change at runtime is for dynamically allocated space.

您的要点和代码注释没有什么意义,因此我决定重新注释您的代码.在每种情况下,文本均指文本上方的代码:

Your bullet points and the code comments make little sense so I've decided to annotate your code afresh. The text refers to the code above the text in each case:

Foo *f = malloc(sizeof(Foo));

好.未初始化的字节已分配,f指向它们.动态分配的空间尚无有效类型.

OK. Uninitialized bytes have been allocated and f points to them. The dynamically allocated space has no effective type yet.

f->n = 1;

动态分配的空间的前sizeof(int)个字节的有效类型设置为int. (*-但请参见脚注)

The effective type of the first sizeof(int) bytes of dynamically allocated space is set to int. (* - but see footnote)

char *buf = malloc(sizeof(Foo));
memcpy(buf, f, sizeof(Foo));

memcpy函数保留复制的对象的有效类型,因此buf指向的空间的前sizeof(int)个字节的前一个有效类型为int.

The memcpy function preserves effective type of objects copied, so the effective type of the first sizeof(int) bytes of the space pointed to by buf, is int.

((Foo *)buf)->n++;

首先,强制转换没有对齐问题,因为malloc空格对于任何类型都正确对齐.进入n的访问,这是可以的,因为((Foo *)buf)->n是类型为int的左值,并且它指定了有效类型为int的对象.因此,我们可以毫无问题地进行读写.

Firstly, the cast does not have an alignment problem because malloc space is correctly aligned for any type. Moving onto the access of n, this is OK because ((Foo *)buf)->n is an lvalue of type int, and it designates an object of effective type int. So we can read and write with no problem.

memcpy(f, buf, sizeof(Foo));

memcpy总是可以的,因为它设置了有效的类型(您的注释建议memcpy在某些情况下可能不适合).此行将f指向的空间的有效类型设置为int(因为源空间的有效类型为int).

memcpy is always OK, as it sets the effective type (your comment suggested that memcpy might not be OK in some cases). This line sets the effective type of the space pointed to by f, to int (since the source space had effective type int).

f->n++;

很好,与上面的((Foo *)buf)->n++相同.

free(buf);
buf = (void *)f;

多余的演员. f指向的空间仍然具有有效类型int,因为这些行都没有写入该空间.

Redundant cast. The space pointed to by f has effective type int still, since neither of those lines wrote to that space.

free(f);

没问题.

脚注:某些人对表达式f->n(或((Foo *)buf)->n具有严格别名)采用不同的解释.他们说f->n被定义为(*f).n,因此相关的有效类型是,而不是f->n的类型.我不同意这种观点,因此我将不作进一步阐述.有人提出了C2X的建议,以澄清这种情况以及其他严格混叠的灰色区域. ,但无论哪种解释,该代码仍然是正确的.

Footnote: Some people take a different interpretation of the expression f->n (or ((Foo *)buf)->n w.r.t. strict aliasing. They say that f->n is defined as (*f).n and therefore the associated effective type is the type of *f, not the type of f->n. I don't agree with that view so I won't expound on it further. There have been proposals for C2X to clarify this situation and other grey areas of strict aliasing. For your particular code, the code is still correct under either interpretation though.

这篇关于与有效类型规则混淆的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆