联合的别名数组
Aliasing array of unions
这是 问题的后续问题。
以下代码在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;
}
虽然 my_copy
看起来做作,但访问模式是由硬件强制执行的(必须对连续对齐的位置进行 2x 32 位写入)。其余的丑陋之处是由于不同开发人员相隔几年编写的几段代码的交集。
问题是,传递给 my_copy
的参数是否有问题?如果只是复制一个union my_type
,我相信应该没问题。不过,我不知道复制数组是否有效。
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.
我不确定是否将其完全归咎于参数,但是您传递了从两个数组派生的指针,然后使用它们来超越这些数组的边界。未定义的行为结果。由此访问的存储可以被认为保持在 main()
的 src
和 dst
数组的范围内,这在形式上并不重要。
实际上,该程序的行为可能与您预期的一样,尽管我发现特定的调用习惯用法非常晦涩。为什么涉及sizeof(union mytype)
?为什么对应的参数名为count
,而实际上是循环迭代次数的八倍?我想我已经弄清楚了,但我不应该对此不确定。
如果要在 union my_type
的两个不相交数组之间进行复制,使用示例的 2x32 位访问模式,那么我会这样写:
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;
}
这与您提供的内容没有太大区别,并且避免了 array-overrun 问题。如果你想保留 sizeof(union my_type)
那么即使将前两个参数的修改类型与 my_copy()
.
结合使用也会更有意义
这是
以下代码在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;
}
虽然 my_copy
看起来做作,但访问模式是由硬件强制执行的(必须对连续对齐的位置进行 2x 32 位写入)。其余的丑陋之处是由于不同开发人员相隔几年编写的几段代码的交集。
问题是,传递给 my_copy
的参数是否有问题?如果只是复制一个union my_type
,我相信应该没问题。不过,我不知道复制数组是否有效。
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.
我不确定是否将其完全归咎于参数,但是您传递了从两个数组派生的指针,然后使用它们来超越这些数组的边界。未定义的行为结果。由此访问的存储可以被认为保持在 main()
的 src
和 dst
数组的范围内,这在形式上并不重要。
实际上,该程序的行为可能与您预期的一样,尽管我发现特定的调用习惯用法非常晦涩。为什么涉及sizeof(union mytype)
?为什么对应的参数名为count
,而实际上是循环迭代次数的八倍?我想我已经弄清楚了,但我不应该对此不确定。
如果要在 union my_type
的两个不相交数组之间进行复制,使用示例的 2x32 位访问模式,那么我会这样写:
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;
}
这与您提供的内容没有太大区别,并且避免了 array-overrun 问题。如果你想保留 sizeof(union my_type)
那么即使将前两个参数的修改类型与 my_copy()
.