【问题标题】:Semantic conflict passing pointer to const pointer to byte array语义冲突将指针传递给 const 指针到字节数组
【发布时间】:2012-09-07 15:14:31
【问题描述】:

我想从下面用原型定义的 OpenSSL 库中调用这个函数:

X509 *d2i_X509(X509 **px, const unsigned char **in, int len);

第二个参数in被定义为const unsigned char **,因为:

  • d2i_X509 不会修改*in 指向的缓冲区中的数据
  • *in 将增加从缓冲区解析的数据量。

现在这个原型是一个问题,因为据我所知,该函数不能以以下方式调用,据我所知,API 是调用它的正常方式(删除了错误管理代码以使事情变得更简单):

unsigned char buffer[2048];
unsigned char * end = buffer;
unsigned char * p = buffer;

end += read(fd, p, 2048);
certlen1 = parseint(&p);
X509 * cert1 = d2i_x509(NULL, &p, certlen1);
certlen2 = parseint(&p);
X509 * cert2 = d2i_x509(NULL, &p, certlen2);

如果我尝试编译上面的代码,它会说:

error: invalid conversion from 'unsigned char**' to 'const unsigned char**'

我理解消息的基本原理(例如解释为 here),但在这种特殊情况下,此基本原理并不适用,因为函数在其文档中声明它只会增加 *in 的值,从不分配指向它的无关指针。

我无法将 p 的类型更改为const unsigned char *,因为上面的代码实际上是简化的,指针隐藏在一些执行读写操作的抽象 IO 对象后面。前一个 IO 对象的好处是保持对称读写代码在一起,可以在我的 IO 对象中使用两个单独的指针进行读写,但这样做的总体好处非常小(如果不是负面的)并添加很多语法噪音。由一些外部无关的 API 调用强制在 IO 对象中进行那种深度的内部更改,看起来真的很费力。

一种解决方案可能是执行强制转换,甚至根本不使用返回的指针值(因为我有 size 参数),但感觉也不对。可能是 d2i_X509 的原型没有包含足够的信息,或者编译器的 const 检查规则在这种情况下过于严格。

应该如何从 C++ 调用这样的 API?现在我只使用演员表,因为我觉得它是较小的邪恶,但有没有更好的方法?

【问题讨论】:

    标签: c++ const-cast


    【解决方案1】:

    首先,这段代码中的+= 没有多大意义:

    p += read(fd, p, 2048);
    

    您正在修改p 以指向刚刚过去您刚刚读取的数据,因此d2i_x509 将读取垃圾。

    我会这样做:

    unsigned char buffer[2048];
    int n = read(fd, buffer, 2048);
    if (n < 0) ..error..;
    const unsigned char * p = buffer;
    X509 * cert1 = d2i_x509(NULL, &p, certlen1);
    X509 * cert2 = d2i_x509(NULL, &p, certlen2);
    int used = p - buffer;  // # of bytes actually parsed by the two calls
    

    未来的任何更改都可以直接对buffer进行。

    编辑:

    好的,然后替换这个:

    X509 * cert1 = d2i_x509(NULL, &p, certlen1);
    

    用这个:

    {
      const unsigned char *q = p;
      X509 * cert1 = d2i_x509(NULL, &q, certlen1);
      p += q - p;
    }
    

    【讨论】:

    • 你在技术上是正确的,但完全不是重点,虽然我的实际代码过于简单,但我做得有点过头了。实际上,我有第二个指针“end”,它通过读取递增,certlen1 和 certlen2 使用从缓冲区开始并沿途递增的 p 进行解析和提取。 p 也存储在一些不透明的对象中,该对象在缓冲区上执行读取和写入以及(检查边界)。虽然可能使内部 p const 是一个真正的负担,但没有明显的好处。换句话说,如果它是玩具,而不是真正的程序,建议的提案将是可能的。
    • 我不确定它是否比强制转换更好(看起来像是破坏 const 检查系统的某种方式),但它绝对是避免强制转换的可能解决方案。
    猜你喜欢
    • 2016-05-18
    • 1970-01-01
    • 2018-08-09
    • 1970-01-01
    • 2019-02-07
    • 1970-01-01
    • 2021-03-09
    • 2012-01-24
    • 1970-01-01
    相关资源
    最近更新 更多