【问题标题】:C++ memcpy and happy access violationC++ memcpy 和快乐访问冲突
【发布时间】:2011-10-14 09:19:20
【问题描述】:

由于某种原因,我无法确定我遇到了访问冲突。

memcpy_s (buffer, bytes_per_line * height, image, bytes_per_line * height);

这是整个功能:

int Flip_Bitmap(UCHAR *image, int bytes_per_line, int height)   
{   
    // this function is used to flip bottom-up .BMP images   

    UCHAR *buffer; // used to perform the image processing   
    int index;     // looping index   

    // allocate the temporary buffer   
    if (!(buffer = (UCHAR *) malloc (bytes_per_line * height)))   
        return(0);   

    // copy image to work area   
    //memcpy(buffer, image, bytes_per_line * height);   
    memcpy_s (buffer, bytes_per_line * height, image, bytes_per_line * height);

    // flip vertically   
    for (index = 0; index < height; index++)   
        memcpy(&image[((height - 1) - index) * bytes_per_line], &buffer[index * bytes_per_line], bytes_per_line);   

    // release the memory   
    free(buffer);   

    // return success   
    return(1);   

} // end Flip_Bitmap   

整个代码: http://pastebin.com/udRqgCfU

要运行它,您需要源目录中的 24 位位图。 这是较大代码的一部分,我正在尝试使 Load_Bitmap_File 函数工作...... 那么,有什么想法吗?

【问题讨论】:

  • 您确定image 具有广告尺寸吗?并且这两个尺寸参数是否正确传递?
  • 你不需要那个临时缓冲区
  • 我认为问题出在image - 而不是bytes_per_line * height
  • 是读写访问冲突吗?
  • biSizeImage 与您用bytes_per_line * height 计算的大小进行比较。举报我们

标签: c++ access-violation memcpy


【解决方案1】:

您遇到了访问冲突,因为很多图像程序没有正确设置biSizeImage。您正在使用的图像可能将biSizeImage 设置为0,因此您没有为图像数据分配任何内存(实际上,您可能分配了4-16 个字节,因为大多数malloc 实现将返回一个非NULL 值,即使请求的分配大小为 0)。因此,当您复制数据时,您正在读取该数组的末尾,这会导致访问冲突。

忽略biSizeImage 参数并自行计算图像大小。记住每条扫描线的大小必须是4字节的倍数,所以需要四舍五入:

// Pseudocode
#define ROUNDUP(value, power_of_2) (((value) + (power_of_2) - 1) & (~((power_of_2) - 1)))
bytes_per_line = ROUNDUP(width * bits_per_pixel/8, 4)
image_size = bytes_per_line * height;

然后只需使用相同的图像大小来读取图像数据并进行翻转。

【讨论】:

  • 就是这样。手动计算图像大小有效。主要程序功能,虽然错误地,图像被拉伸到整个屏幕,但至少 Load_Image_Function 有效。你能告诉我你用过什么运算符~吗?它应该做什么?我真的很想了解#define ROUNDUP(value, power_of_2) (((value) + (power_of_2) - 1) &amp; (~((power_of_2) - 1)))。谢谢帮忙~
  • @Martin:~ 运算符是一元按位否定运算符。它将所有 0 翻转为 1,反之亦然,因此 ~00110101 = 11001010(二进制)。 ~(4-1) 是 0xFFFFFFFC,所以 ROUNDUP(x, 4) 等价于 ((x + 3) &amp; 0xFFFFFFFC),通过加 3 并与底部两位相加,将 x 向上舍入到 4 的下一个倍数。
  • 好的,感谢您的澄清。虽然我仍然不明白为什么当width * bits_per_pixel/8ROUNDUP(width * bits_per_pixel/8, 4) 相同时你需要这个功能。我想一些预防措施。无论如何,谢谢!
  • @Martin:如果width是7,bits_per_pixel是24,那么width * bits_per_pixel/8是21,ROUNDUP(width * bits_per_pixel/8, 4)是24。扫描行中的字节数总是倍数BMP 文件中有 4 个字节,因此每个扫描行有 24 个字节,而不是 21 个。
  • @Martin:3 个杂散字节是padding bytes。它们的存在纯粹是为了使对扫描线数据的访问与处理器的自然字对齐对齐,这在许多情况下会提供更好的性能。填充字节的实际值被完全忽略——它们在内存或磁盘中的值对像素数据或与图像相关的任何其他内容没有任何影响。
【解决方案2】:

正如cmets所说,图片数据不一定是width*height*bytes_per_pixel

内存访问通常在 32 位边界上更快,并且在处理图像时速度通常很重要。因此,图像的行通常会从 4 字节(32 位)边界开始移动

如果图像像素是 32 位(即 RGBA),这不是问题,但如果每个像素有 3 个字节(24 位颜色),那么对于某些图像宽度,列数 * 3 不是 4 的倍数, 然后在每一行的 edn 插入额外的空白字节。

图像格式可能有一个“步幅”宽度或 elemsize 值来告诉您这一点。

【讨论】:

  • 感谢您的澄清:)
【解决方案3】:

您为image 分配bitmap-&gt;bitmapinfoheader.biSizeImage,但继续复制bitmap-&gt;bitmapinfoheader.biWidth * (bitmap-&gt;bitmapinfoheader.biBitCount / 8) * bitmap-&gt;bitmapinfoheader.biHeight 字节的数据。我敢打赌这两个数字不一样。

【讨论】:

  • 你是对的。 bitmap-&gt;bitmapinfoheader.biSizeImage 是 0...谁会期望 MS PAINT 能做到这一点? :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-26
  • 2018-04-16
  • 1970-01-01
  • 1970-01-01
  • 2014-12-25
相关资源
最近更新 更多