为什么将指针作为(char *)传递并转换为(long *)

时间:2018-07-07 00:59:34

标签: c++ mysql pointers polymorphism void-pointers

我知道遗产始终是合理的,但是我想从MariaDB and see if I understand it enough to critique what's going on,来查看这个示例

static int show_open_tables(THD *, SHOW_VAR *var, char *buff) {
  var->type = SHOW_LONG;
  var->value = buff;
  *((long *)buff) = (long)table_cache_manager.cached_tables();
  return 0;
}

在这里,他们正在使用char*,并将其写入var->value which is also a char*。然后,它们在buff中强制将指针指向long并将其类型设置为SHOW_LONG来指示它。

我想知道为什么他们为此使用char*而不使用uintptr_t-尤其是当他们强迫指向long和其他类型的指针时。

规范{-{1}}之前是否不使用uintptr_t来实现C ++中的多态性?

2 个答案:

答案 0 :(得分:2)

这里似乎有两个问题。所以我把答案分开了。

使用char*

使用char*很好。字符类型(charsigned charunsigned char)由C和C ++标准专门处理。 C标准定义了以下用于访问对象的规则:

  

只能通过具有以下类型之一的左值表达式访问对象的存储值:

     
      
  • 与对象的有效类型兼容的类型
  •   
  • 与对象的有效类型兼容的类型的限定版本,
  •   
  • 一种类型,它是与对象的有效类型相对应的有符号或无符号类型,
  •   
  • 一种类型,它是与对象的有效类型的限定版本相对应的有符号或无符号类型,
  •   
  • 在其成员(包括递归地包括子集合或包含的联盟的成员)中包括上述类型之一的集合或联合类型,或
  •   
  • 一种字符类型。
  •   

这实际上意味着字符类型是标准最接近定义“字节”类型的字符(C ++ 17中的std::byte仅定义为enum class byte : unsigned char {}

但是,按照上述规则,将char*强制转换为long*然后分配给它是不正确的(尽管通常在实践中可行)。应该使用memcpy。例如:

long cached_tables = table_cache_manager.cached_tables();
memcpy(buf, &cached_tables, sizeof(cached_tables));

void*也将是一个合理的选择。是否更好是一个意见的问题。我想说的最明确的选择是为char添加一个类型别名,以传达使用它作为字节类型的意图(例如typedef char byte_t)。不过,我想起了几个杰出的库示例,这些示例按原样使用char作为字节类型。例如,Boost存储器映射的文件代码给出了char*,leveldb使用std::string作为字节缓冲区类型(大概是为了利用SSO)。

关于uinptr_t

uintptr_t可选类型,定义为能够保存指针的无符号整数。如果要以整数存储指向对象的地址,则它是适合使用的类型。这不是在这里使用的合适类型。

答案 1 :(得分:0)

  

他们正在使用char *,并且正在将其写入var-> value,这也是char *。然后,他们将指针强制指向buff中的long,并将类型设置为SHOW_LONG来指示它。

或其他。该代码是可怕的。

  

我想知道为什么他们为什么要为此使用char *而不是uintptr_t?尤其是当他们强迫指向long和其他类型的指针时。

谁知道?谁知道他写的时候写的是什么?谁在乎?该代码是可怕的,我们当然不应该尝试从中学习。

  

规范pre-uintptr_t是否不将void *用于C ++中的多态?

是,现在仍然如此。 uintptr_t的目的是定义一个足够容纳指针的整数类型。

  

我想从MariaDB中查看这个示例,看看我是否足够理解它来批评正在发生的事情

您可能对此有所保留,但我当然没有,那只是一个公然的谎言。这样做的方式(如果绝对需要)(显然)是:

static int show_open_tables(THD *, SHOW_VAR *var, long *buff) {

  var->type = SHOW_LONG;
  var->value =  (char *) buff;
  *buff = (long)table_cache_manager.cached_tables();
  return 0;

}

那么至少它不再是定时炸弹了。


嗯,好吧,也许(只是也许)该函数在某个地方的分派表中使用,因此需要(除非您强制转换)具有特定的签名。如果是这样,我当然不会挖掘10,000行代码来找出(而且无论如何,我不能这样做,因为它使我的平板电脑崩溃了很长时间)。

但是,如果有的话,那只会使情况变得更糟。现在,定时炸弹已成为stealth bomber。无论如何,我不相信这是片刻。这只是一件危险的废话。