【问题标题】:Pointer Arithmetic and Read/Write in CC中的指针算术和读/写
【发布时间】:2013-12-10 16:37:20
【问题描述】:

我正在编写一些非常低级的 C 代码来模拟家庭作业项目的“文件系统”。文件系统由固定大小的块(1024B)组成,但允许一个“文件”跨越多个不连续的块。

我需要能够将任何类型的void *buf 写入具有模仿write 的函数的文件。假设我们有以下签名myWrite(int blockNum, void *buf, int nbytes

假设nbytes 大于1024,所以我必须写入多个块。所以我需要做类似的事情:

int remainder = nbytes - 1024;
myWrite(firstBlock, buf, 1024);
myWrite(nextBlock, (buf + 1024), remainder);

myWrite 调用下面的标准write 函数,传入类似的参数。

问题在于指针算术,当我在void* 上进行指针算术时,C 不喜欢。我得到一个EINVALEARGS(取决于Mac 还是Linux)说C 不喜欢我传递给write 系统调用的指针,因为它是通过void 指针算法生成的。

问题是,我不知道我要写什么样的数据类型。有时是 char *,有时是自定义的东西,例如 my_type *,代表程序代码中的结构。

有没有办法解决这个问题?我需要有一个这样的概括性写作。我当前的实现大部分时间都有效,但有时会失败。

【问题讨论】:

  • 假设buf被声明为void *,并且1024是一个字节数,那么(unsigned char *) buf + 1024应该没问题。
  • 这适用于任何数据类型吗?
  • 如果你只是写出字节,那么底层类型是无关紧要的。
  • 我在写调用中仍然收到无效参数。有趣的是,当我做类似的事情但使用 read() 时,我没有收到错误。
  • 虽然形式上不正确,但void * 指针算法应该没有问题,因为 Linux 下的每个主要编译器都在执行预期和记录的操作。我猜,您的 buf 太小或 nbytes - 1024 评估为负数或太大。我建议通过strace 和/或valgrind 运行您的程序

标签: c pointers io filesystems system-calls


【解决方案1】:

问题在于指针运算,当我在 void* 上进行指针运算时,C 不喜欢

没错:C 禁止您将整数添加到void*,因为它不知道如何将数字转换为使指针前进的字节数。通常,乘数可以从指针的类型导出。但是,void* 没有类型,因此 C 禁止对其进行算术运算。

C 不介意您是否对已知大小的其他指针类型进行指针运算。您可以将void* 指针转换为uint8_t* 指针、char* 指针或任何其他指向sizeof(*ptr) 等于1 的类型的指针,并在进行算术运算之前对其进行算术运算操作:

myWrite(nextBlock, ((char*)buf) + 1024, remainder);

函数本身应该继续使用void*

【讨论】:

    【解决方案2】:

    坚持使用void *-pointers。

    当需要按字节进行指针运算时,只需将void *-指针转换为char *(因为sizeof(char) 被定义为等于1):

    int a[2] = {47, 11};
    void * p = &a[0];
    
    printf("%d\n", *((int *)p)); /* Prints 47. */
    
    p = ((char *) p) + sizeof(a[0]); /* Increments p by sizeof(int) bytes. */
    
    printf("%d\n", *((int *)p)); /* Prints 11. */
    

    另外请注意:要键入描述内存量或索引的整数,请使用size_t,因为它保证足够宽以寻址/索引编译代码的机器上的所有内容。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-10-20
      • 1970-01-01
      • 2012-07-27
      • 1970-01-01
      • 2013-06-03
      • 2020-12-17
      相关资源
      最近更新 更多