如何在C语言中实现memcpy的查错功能?

af7jpaap  于 11个月前  发布在  其他
关注(0)|答案(3)|浏览(119)

这是一个学习练习。我试图通过在复制操作开始之前通知用户复制操作是通过还是失败来增强memcpy。我最大的问题如下。如果我分配两个100字节的char数组,并有两个指针引用每个数组,我怎么知道我复制的方向?如果我将第一个数组中的所有内容复制到第二个数组中,如何确保用户不会复制原始数组?
我目前的解决方案比较指针与目标数组大小的距离。如果大小之间是小于我说一个覆盖将发生。但如果它是在另一个方向复制呢?我只是有点困惑。

int memcpy2(void *target, void *source, size_t nbytes) {
    char * ptr1 = (char *)target;
    char * ptr2 = (char *)source;

    int i, val;

    val = abs(ptr1 - ptr2);
    printf("%d, %d\n", val, nbytes + 0);
    if (val > nbytes) {
        for (i = 0; i < val; i++){
            ptr1[i] = ptr2[i];
        }
        return 0;  /*success */
    }
    return -1; /* error */
}


int main(int argc, char **argv){

  char src [100] = "Copy this string to dst1";
  char dst [20];
  int p;
  p = memcpy2(dst, src, sizeof(dst));

    if (p == 0)
        printf("The element\n'%s'\nwas copied to \n'%s'\nSuccesfully\n", src, dst);
    else
        printf("There was an error!!\n\nWhile attempting to copy the elements:\n '%s'\nto\n'%s', \n Memory was overlapping", src, dst);
    return 0;

}
f45qwnt8

f45qwnt81#

确定两个内存范围是否重叠的唯一 * 便携 * 方法是:

int overlap_p(void *a, void *b, size_t n)
{
    char *x = a, *y =  b;
    for (i=0; i<n; i++) if (x+i==y || y+i==x) return 1;
    return 0;
}

这是因为指针与关系运算符的比较是未定义的,除非它们指向同一个数组。实际上,这种比较在大多数现实世界的实现中都有效,所以你可以这样做:

int overlap_p(void *a, void *b, size_t n)
{
    char *x = a, *y =  b;
    return (x<=y && x+n>y) || (y<=x && y+n>x);
}

我希望我的逻辑是正确的;你应该检查一下。如果你想假设你可以接受任意指针的差异,你可以进一步简化它。

ylamdve6

ylamdve62#

你要检查的是源在内存中相对于目标的位置:
如果源在目的地之前(即,source < destination),那么你应该从最后开始。如果源在后面,则从头开始。如果它们是相等的,你不必做任何事情(平凡的情况)。
这里有一些粗略的ASCII图形来可视化这个问题。

|_;_;_;_;_;_|          (source)
      |_;_;_;_;_;_|    (destination)
            >-----^    start from the end to shift the values to the right

      |_;_;_;_;_;_|    (source)
|_;_;_;_;_;_|          (destination)
^-----<                 start from the beginning to shift the values to the left

在下面一个非常准确的评论之后,我应该补充说,你可以使用指针的差异(目的地-源),但为了安全起见,事先将这些指针转换为char *。
在您当前的设置中,我不认为您可以检查操作是否会失败。你的memcpy原型阻止你做任何形式的检查,并且使用上面给出的决定如何复制的规则,操作将成功(除了任何其他考虑因素,如之前的内存损坏或无效指针)。

9q78igpj

9q78igpj3#

我不相信“试图通过在复制操作开始之前通知用户复制操作是通过还是失败来增强memcpy”是一个格式良好的概念。
首先,memcpy()不会在正常意义上成功或失败。它只是复制数据,如果它在源数组之外读取或在目标数组之外写入,可能会导致错误/异常,它也可能在这些数组之一之外读取或写入而不会导致任何错误/异常,只是默默地破坏数据。当我说“memcpy这样做”时,我并不仅仅是在谈论C stdlib memcpy的实现,而是在谈论任何具有相同签名的函数--它没有足够的信息来做其他的事情。
其次,如果你对“成功”的定义是“假设缓冲区足够大,但可能会重叠,将数据从源复制到dst,而不会在复制时绊倒自己”--这确实是memmove()所做的,而且总是可能的。同样,没有“返回失败”的情况。如果缓冲区不重叠,这很容易,如果源重叠的目的地结束,那么你只是复制字节从开始;如果源代码与目标代码的开头部分重叠,那么你只需从末尾开始一个字节一个字节地复制。这就是memmove()的作用。
第三,在编写这类代码时,必须非常小心指针运算(包括加法、减法和数组索引)的溢出情况。在val = abs(ptr1 - ptr2)中,ptr1 - ptr2可能是一个非常大的数字,它将是无符号的,所以abs()不会对它做任何事情,而int是存储它的错误类型。你知道的

相关问题