【问题标题】:Passing a constant integer when function expects a pointer当函数需要一个指针时传递一个常量整数
【发布时间】:2011-05-24 21:15:39
【问题描述】:

将常量整数值传递给需要指针的函数的最佳/最规范的方法是什么?

例如,write 函数

write (int filedes, const void *buffer, size_t size);

假设我只想写一个字节(a 1),我会这样认为:

write (fd, 1, 1);

但我显然得到了警告

warning: passing argument 2 of 'write' makes pointer from integer without a cast

我知道我能做到

int i = 1;
write (fd, &i, 1);

但这有必要吗?不需要声明/初始化新变量的最正确方法是什么?

【问题讨论】:

  • 您的“我知道我能做到……”示例不正确。你想说char i = 1; write(fd, &i, 1);
  • @Rob:是的,你说得对。在这种情况下,我只写过 1 或 0(它是一条控制线),所以我想我忽略了它不正确但有效的事实。
  • 让我猜猜……你有一个小端序机器,对吧?
  • "incorrect-but-working" - 我会尝试将其用于错误分类(请参阅stackoverflow.com/questions/6114684/…)。很快我就会在那次会议上把他们打死。
  • 超级 necro-post,但我要补充一点,我会创建第二个函数(例如,称之为“put”),它只写入一个字节,并执行任何必要的类型转换废话来实现这一点工作。在我的具有任何类型的读/写操作的库中,我通常为单个字节(或对象)创建一个单数动词(put / get / read / write),为多个需要的复数动词(puts / gets / reads / writes)缓冲区和长度。您也可以使用 stdlib 的方式并执行“put”和“putn”……我只是觉得这有点难看。

标签: c pointers casting


【解决方案1】:

在 C89/90 中,您通常不能在不声明新变量的情况下执行此操作。 C 中的指针的问题是它们总是指向左值。左值是在内存中有位置的东西。所以,为了给你的函数提供正确的参数,你需要一些在内存中有位置的东西。这通常需要一个定义,即一个对象、一个变量。 C 中的常量不是左值,所以你不能在那里使用常量。介于常量和变量之间的东西是文字。 C89/90 只有一种文字:字符串文字。字符串文字是左值,但不是变量。因此,您可以使用字符串文字作为write 的第二个参数。

在 C99 中,文字的概念已扩展到字符串文字之外。在 C99 中,您还可以为此目的使用 复合文字,它也恰好是左值。在您的示例中,您可以将函数称为

write(fd, (char[]) { 1 }, 1)

但此功能仅在 C99 中可用。

【讨论】:

  • +1,我不知道。太糟糕了 GCC 仍然默认为 C90,但至少 Intel C 编译它没有额外的标志。
  • 不错。详细说明所描述的 C90 解决方案:write( fd, "\x1", 1);。我可能真的会在某个时候使用它;我不确定我是否对此感到高兴。
  • 采用 C99 方法有什么好处吗?除了不需要额外变量的明显事实之外?也就是说,用字符串常量说@Michael Burr 的版本?
  • 我选择了这个,因为它是对我的问题最直接的回答。但是,我可能不会使用这种方法,除非有一个非常好的论据,我认为没有。
【解决方案2】:

对于您引用的具体案例,您可以这样做:

write(fd, "\001", 1);

但是,更一般地说,您必须做您抱怨的事情。您必须在获取其地址之前声明一个对象:

 SomeType i;
 SomeFUnction(&i);

【讨论】:

  • 请注意,我的回答仅对 C90 正确。有关如何使用新奇 C99 的一个很好的示例,请参阅 @AndreyT。
  • 我认为这比 C99 选项更清晰(并且适用于 C90、C99 或 C++)。我不确定我是否赞同使用它。但正如我在对 AndreyT 的回答的评论中提到的那样,现在我已经看到了,我可能会看到它。
【解决方案3】:

是的,这是必要的。在 C 中没有其他同样清楚的方法可以做到这一点,因为您无法获取/获取指向临时地址的指针。

(而且,正如@rob 已经说过的,您应该使用char 的地址。您的示例是不可移植的。)

编辑:查看@AndreyT 的回答并将您的编译器设置为C99 模式。

【讨论】:

    【解决方案4】:

    整数不是指针。如果你传给它一个,它将取消引用虚拟地址 1 并死掉。您必须创建该变量并传递其地址。

    【讨论】:

      【解决方案5】:

      Write 需要一个地址作为第二个参数 - 使用它。

      【讨论】:

      • “与它共处”我没有问题。我只是好奇,因为我觉得这是一个相当普遍的情况。
      【解决方案6】:

      您可以使用drprintf() 打印到文件描述符。它类似于fprintf() 打印到FILE *

      int dprintf(int fd, const char *format, ...);
      

      详情请见man 3 dprintf

      函数 dprintf() 和 vdprintf()(在 glibc2 库中找到)与 fprintf(3) 和 vfprintf(3) 完全类似,除了它们输出到文件描述符 fd 而不是标准输出流。

      它符合 POSIX.1,而不是通用的。

      【讨论】:

      • 嗯,我不确定这如何回答我的问题。
      • 您想在不使用临时变量的情况下写入单个字节。你可以这样做:dprintf(fd,"%c",1);.
      • 啊,我在发呆。由于我正在写入串行线路,因此我非常愿意使用 write 而不是更高级别的 io 函数。据我了解,与fprintf 等相比,涉及的缓冲更少(除非我弄错了)
      【解决方案7】:
      write(var, new int(4))
      

      这似乎有效。不确定这有多好,因为我没有太多使用 C++。 让我知道这是否是一种不好的方法。

      【讨论】:

      • 你刚刚成功创建了内存泄漏。
      猜你喜欢
      • 2018-04-14
      • 1970-01-01
      • 2022-01-13
      • 2017-07-23
      • 1970-01-01
      • 2015-05-09
      • 2023-03-30
      • 1970-01-01
      • 2018-09-16
      相关资源
      最近更新 更多