联合数组的别名

发布于 2025-01-14 09:13:33 字数 969 浏览 3 评论 0原文

这是问题的后续问题。

以下代码位于编译器资源管理器上。

#include <stddef.h>
#include <stdint.h>

union my_type
{
    uint8_t m8[8];
    uint16_t m16[4];
    uint32_t m32[2];
    uint64_t m64;
};

void my_copy(uint32_t volatile *restrict dst, uint32_t const *restrict src, size_t const count)
{
    for (size_t i = 0; i < count / 8; ++i)
    {
        *dst++ = *src++;
        *dst++ = *src++;
    }
}

int main(int argc, char *argv[])
{
    union my_type src[100];
    union my_type dst[200];

    my_copy(dst[42].m32, src[10].m32, sizeof(union my_type) * 60);
    
    return 0;
}

虽然 my_copy 看起来很人为,但访问模式是由硬件强制的(必须对连续对齐的位置进行 2x 32 位写入)。其余的丑陋之处是由相隔几年的不同开发人员编写的几段代码的交集造成的。

问题是,传递给 my_copy 的参数有问题吗?如果这只是复制一个union my_type,我相信就可以了。不过,我不知道复制数组是否有效。

This is a follow-up question to this question.

The following code is on Compiler Explorer.

#include <stddef.h>
#include <stdint.h>

union my_type
{
    uint8_t m8[8];
    uint16_t m16[4];
    uint32_t m32[2];
    uint64_t m64;
};

void my_copy(uint32_t volatile *restrict dst, uint32_t const *restrict src, size_t const count)
{
    for (size_t i = 0; i < count / 8; ++i)
    {
        *dst++ = *src++;
        *dst++ = *src++;
    }
}

int main(int argc, char *argv[])
{
    union my_type src[100];
    union my_type dst[200];

    my_copy(dst[42].m32, src[10].m32, sizeof(union my_type) * 60);
    
    return 0;
}

While my_copy looks contrived, the access pattern is forced by hardware (must have 2x 32-bit writes to consecutive aligned locations). The rest of the ugliness is due to the intersection of a couple of sections of code that were written by different developers a couple of years apart.

The question is, are the arguments passed to my_copy an issue? If this was just to copy a single union my_type, I believe that it would be ok. I don't know if that is valid to copy an array, though.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

薄荷→糖丶微凉 2025-01-21 09:13:33

问题是,传递给 my_copy 的参数有问题吗?如果这只是复制单个联合my_type,我相信就可以了。不过,我不知道复制数组是否有效。

我不确定是否将其归咎于参数,确切地说,但是您传递从两个数组派生的指针,然后使用它们来超出这些数组的边界。未定义的行为结果。由此访问的存储可以被认为保留在 main()srcdst 数组的范围内,这在形式上并不重要。

在实践中,程序的行为可能如您所期望的那样,尽管我发现特定的调用习惯非常晦涩。为什么要涉及sizeof(union mytype)?为什么相应的参数名为 count,而它实际上是循环迭代次数的八倍?我想我已经弄清楚了,但我不应该对此感到不确定。

如果您想使用示例的 2x32 位访问模式在两个不相交的 union my_type 数组之间进行复制,那么我会这样写:

void my_copy(volatile union mytype * restrict dst,
        volatile const union my_type * restrict src, size_t byte_count) {
    // TODO: validate (or assert) that byte_count is a multiple of 8
    for (size_t i = 0; i < byte_count / 8; ++i) {
        dst->m32[0] = src->m32[0];
        dst->m32[1] = src->m32[1];
        ++dst;
        ++src;
    }
}

int main(int argc, char *argv[]) {
    union my_type src[100];
    union my_type dst[200];

    my_copy(dst + 42, src + 10, 8 * 60);
    
    return 0;
}

这与您所呈现的并没有太大不同,而且它避免了数组溢出问题。如果您想保留 sizeof(union my_type) ,那么与 my_copy() 的前两个参数的修订类型结合起来,即使这样也会更有意义。

The question is, are the arguments passed to my_copy an issue? If this was just to copy a single union my_type, I believe that it would be ok. I don't know if that is valid to copy an array, though.

I'm not sure whether to blame it on the arguments, exactly, but you pass pointers derived from two arrays, and then use them to overrun the bounds of those arrays. Undefined behavior results. That the storage thereby accessed can be considered to stay within the bounds main()'s src and dst arrays does not formally matter.

In practice, the program probably behaves as you expect, though I find the particular calling idiom extremely obscure. Why is sizeof(union mytype) involved? Why is the corresponding parameter named count, when it is actually eight times the number of loop iterations? I think I have figured it out, but I shouldn't have to be uncertain about that.

If you want to copy between two disjoint arrays of union my_type, using the 2x32-bit access pattern of the example, then I would write it like this:

void my_copy(volatile union mytype * restrict dst,
        volatile const union my_type * restrict src, size_t byte_count) {
    // TODO: validate (or assert) that byte_count is a multiple of 8
    for (size_t i = 0; i < byte_count / 8; ++i) {
        dst->m32[0] = src->m32[0];
        dst->m32[1] = src->m32[1];
        ++dst;
        ++src;
    }
}

int main(int argc, char *argv[]) {
    union my_type src[100];
    union my_type dst[200];

    my_copy(dst + 42, src + 10, 8 * 60);
    
    return 0;
}

That's not too different from what you present, and it avoids the array-overrun issue. And if you want to keep sizeof(union my_type) then even that would make a bit more sense in conjunction with the revised types of the first two parameters to my_copy().

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文