【问题标题】:How to check if mpz_t number is initialized using GMP?如何检查 mpz_t 编号是否使用 GMP 初始化?
【发布时间】:2019-07-31 17:19:13
【问题描述】:

在 c++ 中使用 GMP 库。我有一个函数,它接收指向 mpz_t 数字的指针并从中设置另一个 gmp_z 数字。我需要一种方法来检查 *_amount 之前是否已初始化。

void f(mpz_t* _amount)
{
    mpz_t amount;
    mpz_init(amount);

    if(!_amount){
        throw std::bad_alloc();
    }

    mpz_set(amount, *_amount);
}

如何检查 _amount 之前是否已初始化?

【问题讨论】:

  • 我很确定你不知道。我的意思是,例如,您如何检查 int 是否已初始化?
  • 顺便问一下,你为什么要传递一个指向mpz_t 的指针? mpz_t 是一个引用类型。
  • 你能使用C++接口吗? gmplib.org/manual/C_002b_002b-Interface-General.html你为什么用C接口?
  • 确实,mpz_t 是一个数组类型。但是数组参数衰减为指针。
  • 无法检查 POD 类型是否已初始化。

标签: c++ gmp bignum


【解决方案1】:

这是 C 语言中的不良做法 - 故事结束。您检查_amount 是否已初始化。 GMP 库经过高度优化,确保正确初始化mpz_t 对象是唯一正确的方法。所以mpz_t 对象可能看起来已初始化,但除非mpz_init(_amount) 已被使用,否则这些字段可能是未初始化的垃圾。

_amount 是否已经设置无关紧要。看mpz/set.c

void
mpz_set (mpz_ptr w, mpz_srcptr u)
{
  mp_ptr wp, up;
  mp_size_t usize, size;

  usize = SIZ(u);
  size = ABS (usize);

  wp = MPZ_REALLOC (w, size);

  up = PTR(u);

  MPN_COPY (wp, up, size);
  SIZ(w) = usize;
}

显然,如果mpz_t(参见:gmp-h.in)的字段未初始化,它们可能是垃圾。 mpz_set 可以在尚未分配的连续内存上执行 realloc。如果你幸运的话,那就是一场崩溃。如果不是,程序将继续处于未定义状态。

mpz_t 视为“C 对象”可能会很有用。在初始化之前,它们是无效的(并且不能正确使用)。我还要强调,当谈到 GMP(多精度算术)的要求时,初始化变量(例如,为零)的“开销”绝对可以忽略不计。

所以让我们假设_amount 已正确初始化:


mpz_init(_amount); /* correctly sets mpz_t and assigns (0). */

/* (maybe `_amount` isn't (0)... that's OK too) */

void f (mpz_t *_amount)
{
    mpz_t amount;
    mpz_init(amount);

    /* unless using the GMP C++ interface, there's no definition
     * for the (!) operator. However `mpz_sgn` can be used here: */

    if (mpz_sgn(_amount) == 0) /* (_amount == 0 : exit condition?) */
    {
        mpz_clear(_amount); /* free space occupied by (_amount) */

        /* NOTE: this is NOT C++ with object unwinding! (amount) will
         * potentially leak resources! */

        mpz_clear(amount);
        throw std::bad_alloc {}; /* no leaks; deallocated storage. */
    }

    /* since (amount) will need to be deallocated, and we don't want
     * to deal with assignment errors - we simply 'swap' contents. */

    mpz_swap(_amount, amount); mpz_clear(amount);
}

我觉得你在这里混合了范式。 throw 在本质上是 C 代码中的使用会迫使您手动清理,而 mpz_t 不是不是一个 C++ 对象,它“构造”为默认值,或者在销毁时释放所有资源/ 超出范围。

您可能会发现GMP C++ interface 更适合对您的代码进行原型设计。 mpz_class 充当 C++ 类,在实例化时进行初始化,并在其作用域结束时调用它的析构函数。

现在您正在错误地混合 C/C++,并且让自己容易受到许多错误的影响,其中一些可能不会立即导致崩溃 - 这些可能是最难确定的...

【讨论】:

  • 感谢您的完整回答@Brett。为什么使用 mpz_sgn(amount) 作为退出条件?预期数字可以为零。无论如何,我现在无法更改代码以使用 c++ 接口。我们在您提议的代码中留下了哪些错误?
【解决方案2】:

由于 _amount 是指针,因此您可以检查 null 或 void 以确保它是否已初始化。

谢谢

【讨论】:

  • 其实我是在检查指针_amount是否不为NULL,但现在我要的是指针的内容。
猜你喜欢
  • 2017-06-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-19
  • 1970-01-01
相关资源
最近更新 更多