为什么C中的这些内联GMP函数在调用时会导致未定义的引用错误?

时间:2017-01-28 04:59:26

标签: c gcc gmp

我最近在Ubuntu 16.04上安装了GMP库。我试图编译一些程序,比如C ++中的这个阶乘计算器,以确保一切正常。

#include <gmp.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <iostream>

void fact(int n)
{
    int i;
    mpz_t p;
    mpz_init_set_ui(p,1); /* p = 1 */
    for (i=1; i <= n ; ++i)
    {
            mpz_mul_ui(p,p,i); /* p = p * i */
    }
    printf ("%d!  =  ", n);
    mpz_out_str(stdout,10,p);
    std::cout<<"\n";
    mpz_clear(p);
}

int main(int argc, char * argv[])
{
    int n;
    if (argc <= 1)
    {
            printf ("Usage: %s <number> \n", argv[0]);
            return 2;
    }
    n = atoi(argv[1]);
    assert( n >= 0);
    fact(n);
    return 1;
}

我使用此命令成功编译了此程序 - g++ foo.cpp -o bar -lgmp

我也可以使用./bar INT成功运行该程序。

问题

当我尝试使用此命令(gcc gmp-chudnovsky.c -o pi -lgmp -lm -std=gnu11)从gmplib.org编译gmp-chudnovsky.c时,每次调用内联函数时都会抛出这些错误:

$ sudo gcc gmp-chudnovsky.c -o pi -lgmp -lm -std=gnu11

/tmp/ccwzMQ8N.o: In function `fac_remove_gcd':
gmp-chudnovsky.c:(.text+0x798): undefined reference to `fac_resize'
gmp-chudnovsky.c:(.text+0x9da): undefined reference to `fac_compact'
gmp-chudnovsky.c:(.text+0x9e6): undefined reference to `fac_compact'
/tmp/ccwzMQ8N.o: In function `bs':
gmp-chudnovsky.c:(.text+0xd48): undefined reference to `fac_set_bp'
gmp-chudnovsky.c:(.text+0xd6f): undefined reference to `fac_mul_bp'
gmp-chudnovsky.c:(.text+0xdc2): undefined reference to `fac_set_bp'
gmp-chudnovsky.c:(.text+0xdfb): undefined reference to `fac_mul_bp'
gmp-chudnovsky.c:(.text+0xe34): undefined reference to `fac_mul_bp'
gmp-chudnovsky.c:(.text+0x1197): undefined reference to `fac_mul'
gmp-chudnovsky.c:(.text+0x1228): undefined reference to `fac_mul'
/tmp/ccwzMQ8N.o: In function `main':
gmp-chudnovsky.c:(.text+0x18e4): undefined reference to `fac_init'
gmp-chudnovsky.c:(.text+0x1901): undefined reference to `fac_init'
gmp-chudnovsky.c:(.text+0x1931): undefined reference to `fac_init'
gmp-chudnovsky.c:(.text+0x193b): undefined reference to `fac_init'
gmp-chudnovsky.c:(.text+0x1a61): undefined reference to `fac_clear'
gmp-chudnovsky.c:(.text+0x1a6b): undefined reference to `fac_clear'
gmp-chudnovsky.c:(.text+0x1aef): undefined reference to `fac_clear'
gmp-chudnovsky.c:(.text+0x1b0c): undefined reference to `fac_clear'
gmp-chudnovsky.c:(.text+0x1b46): undefined reference to `fac_clear'
/tmp/ccwzMQ8N.o:gmp-chudnovsky.c:(.text+0x1b55): more undefined references to `fac_clear' follow
collect2: error: ld returned 1 exit status

这些功能的含义如下:

inline void
fac_resize(fac_t f, long int s)
{
  if (f[0].max_facs < s) {
    fac_clear(f);
    fac_init_size(f, s);
  }
}

/* remove factors of power 0 */
inline void
fac_compact(fac_t f)
{
  long int i, j;
  for (i=0, j=0; i<f[0].num_facs; i++) {
    if (f[0].pow[i]>0) {
      if (j<i) {
          f[0].fac[j] = f[0].fac[i];
    f[0].pow[j] = f[0].pow[i];
      }
      j++;
    }
  }
  f[0].num_facs = j;
}

/* f = base^pow */
inline void
fac_set_bp(fac_t f, unsigned long base, long int pow)
{
  long int i;
  assert(base<sieve_size);
  for (i=0, base/=2; base>0; i++, base = sieve[base].nxt) {
    f[0].fac[i] = sieve[base].fac;
    f[0].pow[i] = sieve[base].pow*pow;
  }
  f[0].num_facs = i;
  assert(i<=f[0].max_facs);
}

/* f *= base^pow */
inline void
fac_mul_bp(fac_t f, unsigned long base, unsigned long pow)
{
  fac_set_bp(ftmp, base, pow);
  fac_mul(f, ftmp);
}

/* f *= g */
inline void
fac_mul(fac_t f, fac_t g)
{
  fac_t tmp;
  fac_resize(fmul, f[0].num_facs + g[0].num_facs);
  fac_mul2(fmul, f, g);
  tmp[0]  = f[0];
  f[0]    = fmul[0];
  fmul[0] = tmp[0];
}

inline void
fac_init(fac_t f)
{
  fac_init_size(f, INIT_FACS);
}

inline void
fac_clear(fac_t f)
{
  free(f[0].fac);
}

引用函数的位置:

在函数fac_remove_gcd中:

/* f /= gcd(f,g), g /= gcd(f,g) */
void
fac_remove_gcd(mpz_t p, fac_t fp, mpz_t g, fac_t fg)
{
  long int i, j, k, c;
  /* VV undefined reference VV */
  fac_resize(fmul, min(fp->num_facs, fg->num_facs));
  for (i=j=k=0; i<fp->num_facs && j<fg->num_facs; ) {
    if (fp->fac[i] == fg->fac[j]) {
      c = min(fp->pow[i], fg->pow[j]);
      fp->pow[i] -= c;
      fg->pow[j] -= c;
      fmul->fac[k] = fp->fac[i];
      fmul->pow[k] = c;
      i++; j++; k++;
    } else if (fp->fac[i] < fg->fac[j]) {
      i++;
    } else {
      j++;
    }
  }
  fmul->num_facs = k;
  assert(k <= fmul->max_facs);

  if (fmul->num_facs) {
    bs_mul(gcd, 0, fmul->num_facs);
#if HAVE_DIVEXACT_PREINV
    mpz_invert_mod_2exp (mgcd, gcd);
    mpz_divexact_pre (p, p, gcd, mgcd);
    mpz_divexact_pre (g, g, gcd, mgcd);
#else
#define SIZ(x) x->_mp_size
    mpz_divexact(p, p, gcd);
    mpz_divexact(g, g, gcd);
#endif
/* VV undefined reference VV */
    fac_compact(fp);
    fac_compact(fg);
  }
}

在函数bs中:

/* binary splitting */
void
bs(unsigned long a, unsigned long b, unsigned gflag, long int level)
{
  unsigned long i, mid;
  int ccc;

  if (b-a==1) {
    /*
      g(b-1,b) = (6b-5)(2b-1)(6b-1)
      p(b-1,b) = b^3 * C^3 / 24
      q(b-1,b) = (-1)^b*g(b-1,b)*(A+Bb).
    */
    mpz_set_ui(p1, b);
    mpz_mul_ui(p1, p1, b);
    mpz_mul_ui(p1, p1, b);
    mpz_mul_ui(p1, p1, (C/24)*(C/24));
    mpz_mul_ui(p1, p1, C*24);

    mpz_set_ui(g1, 2*b-1);
    mpz_mul_ui(g1, g1, 6*b-1);
    mpz_mul_ui(g1, g1, 6*b-5);

    mpz_set_ui(q1, b);
    mpz_mul_ui(q1, q1, B);
    mpz_add_ui(q1, q1, A);
    mpz_mul   (q1, q1, g1);
    if (b%2)
      mpz_neg(q1, q1);

    i=b;
    while ((i&1)==0) i>>=1;
    fac_set_bp(fp1, i, 3);  /*  b^3 */
    fac_mul_bp(fp1, 3*5*23*29, 3);
    fp1[0].pow[0]--;

    fac_set_bp(fg1, 2*b-1, 1);  /* 2b-1 */
    fac_mul_bp(fg1, 6*b-1, 1);  /* 6b-1 */
    fac_mul_bp(fg1, 6*b-5, 1);  /* 6b-5 */

    if (b>(int)(progress)) {
      printf("."); fflush(stdout);
      progress += percent*2;
    }

  } else {
    /*
      p(a,b) = p(a,m) * p(m,b)
      g(a,b) = g(a,m) * g(m,b)
      q(a,b) = q(a,m) * p(m,b) + q(m,b) * g(a,m)
    */
    mid = a+(b-a)*0.5224;     /* tuning parameter */
    bs(a, mid, 1, level+1);

    top++;
    bs(mid, b, gflag, level+1);
    top--;

    if (level == 0)
      puts ("");

    ccc = level == 0;

    if (ccc) CHECK_MEMUSAGE;

    if (level>=4) {           /* tuning parameter */
#if 0
      long t = cputime();
#endif
      fac_remove_gcd(p2, fp2, g1, fg1);
#if 0
      gcd_time += cputime()-t;
#endif
    }

    if (ccc) CHECK_MEMUSAGE;
    mpz_mul(p1, p1, p2);

    if (ccc) CHECK_MEMUSAGE;
    mpz_mul(q1, q1, p2);

    if (ccc) CHECK_MEMUSAGE;
    mpz_mul(q2, q2, g1);

    if (ccc) CHECK_MEMUSAGE;
    mpz_add(q1, q1, q2);

    if (ccc) CHECK_MEMUSAGE;
    fac_mul(fp1, fp2);

    if (gflag) {
      mpz_mul(g1, g1, g2);
      fac_mul(fg1, fg2);
    }
  }

  if (out&2) {
    printf("p(%ld,%ld)=",a,b); fac_show(fp1);
    if (gflag)
      printf("g(%ld,%ld)=",a,b); fac_show(fg1);
  }
}

在函数main中:

int
main(int argc, char *argv[])
{
  mpf_t  pi, qi;
  long int d=100, i, depth=1, terms;
  unsigned long psize, qsize;
  long begin, mid0, mid1, mid2, mid3, mid4, end;

  prog_name = argv[0];

  if (argc>1)
    d = strtoul(argv[1], 0, 0);
  if (argc>2)
    out = atoi(argv[2]);

  terms = d/DIGITS_PER_ITER;
  while ((1L<<depth)<terms)
    depth++;
  depth++;
  percent = terms/100.0;
  printf("#terms=%ld, depth=%ld\n", terms, depth);

  begin = cputime();
  printf("sieve   "); fflush(stdout);

  sieve_size = max(3*5*23*29+1, terms*6);
  sieve = (sieve_t *)malloc(sizeof(sieve_t)*sieve_size/2);
  build_sieve(sieve_size, sieve);

  mid0 = cputime();
  printf("time = %6.3f\n", (double)(mid0-begin)/1000);

  /* allocate stacks */
  pstack = malloc(sizeof(mpz_t)*depth);
  qstack = malloc(sizeof(mpz_t)*depth);
  gstack = malloc(sizeof(mpz_t)*depth);
  fpstack = malloc(sizeof(fac_t)*depth);
  fgstack = malloc(sizeof(fac_t)*depth);
  for (i=0; i<depth; i++) {
    mpz_init(pstack[i]);
    mpz_init(qstack[i]);
    mpz_init(gstack[i]);
    /* VV undefined reference VV */
    fac_init(fpstack[i]);
    fac_init(fgstack[i]);
  }
  mpz_init(gcd);
#if HAVE_DIVEXACT_PREINV
  mpz_init(mgcd);
#endif
  /* VV undefined reference VV */
  fac_init(ftmp);
  fac_init(fmul);

  /* begin binary splitting process */
  if (terms<=0) {
    mpz_set_ui(p2,1);
    mpz_set_ui(q2,0);
    mpz_set_ui(g2,1);
  } else {
    bs(0,terms,0,0);
  }

  mid1 = cputime();
  printf("\nbs      time = %6.3f\n", (double)(mid1-mid0)/1000);
  printf("   gcd  time = %6.3f\n", (double)(gcd_time)/1000);

  /* printf("misc    "); fflush(stdout); */

  /* free some resources */
  free(sieve);

#if HAVE_DIVEXACT_PREINV
  mpz_clear(mgcd);
#endif
  mpz_clear(gcd);
  /* VV undefined reference VV */
  fac_clear(ftmp);
  fac_clear(fmul);

  for (i=1; i<depth; i++) {
    mpz_clear(pstack[i]);
    mpz_clear(qstack[i]);
    mpz_clear(gstack[i]);
    /* VV undefined reference VV */
    fac_clear(fpstack[i]);
    fac_clear(fgstack[i]);
  }

  mpz_clear(gstack[0]);
  /* VV undefined reference VV */
  fac_clear(fpstack[0]);
  fac_clear(fgstack[0]);

  free(gstack);
  free(fpstack);
  free(fgstack);

  /* prepare to convert integers to floats */
  mpf_set_default_prec((long int)(d*BITS_PER_DIGIT+16));

  /*
      p*(C/D)*sqrt(C)
    pi = -----------------
         (q+A*p)
  */

  psize = mpz_sizeinbase(p1,10);
  qsize = mpz_sizeinbase(q1,10);

  mpz_addmul_ui(q1, p1, A);
  mpz_mul_ui(p1, p1, C/D);

  mpf_init(pi);
  mpf_set_z(pi, p1);
  mpz_clear(p1);

  mpf_init(qi);
  mpf_set_z(qi, q1);
  mpz_clear(q1);

  free(pstack);
  free(qstack);

  mid2 = cputime();
  /* printf("time = %6.3f\n", (double)(mid2-mid1)/1000); */

  /* initialize temp float variables for sqrt & div */
  mpf_init(t1);
  mpf_init(t2);
  /* mpf_set_prec_raw(t1, mpf_get_prec(pi)); */

  /* final step */
  printf("div     ");  fflush(stdout);
  my_div(qi, pi, qi);
  mid3 = cputime();
  printf("time = %6.3f\n", (double)(mid3-mid2)/1000);

  printf("sqrt    ");  fflush(stdout);
  my_sqrt_ui(pi, C);
  mid4 = cputime();
  printf("time = %6.3f\n", (double)(mid4-mid3)/1000);

  printf("mul     ");  fflush(stdout);
  mpf_mul(qi, qi, pi);
  end = cputime();
  printf("time = %6.3f\n", (double)(end-mid4)/1000);

  printf("total   time = %6.3f\n", (double)(end-begin)/1000);
  fflush(stdout);

  printf("   P size=%ld digits (%f)\n"
     "   Q size=%ld digits (%f)\n",
     psize, (double)psize/d, qsize, (double)qsize/d);

  /* output Pi and timing statistics */
  if (out&1)  {
    printf("pi(0,%ld)=\n", terms);
    mpf_out_str(stdout, 10, d+2, qi);
    printf("\n");
  }

  /* free float resources */
  mpf_clear(pi);
  mpf_clear(qi);

  mpf_clear(t1);
  mpf_clear(t2);
  exit (0);
}

困境

我在这个帖子https://ubuntuforums.org/showthread.php?t=2209074中发现了类似的问题,但是根据解决方案,我给出了与以前相同的错误。

此外,程序中的其他内联函数在调用时不会出现undefined reference错误,例如fac_resetfac_init_sizefac_mul2;我相信这是因为它们只是从问题函数中调用过来。

我是否对与使用内联函数编译代码相关的一些信息一无所知,或者这是我遇到的一个独特问题?

希望我提供了所需的任何信息和背景信息,但如果需要,我很乐意提供任何内容。

编辑:我刚刚为所有内联函数添加了静态,程序现在编译,但我不知道为什么会有效。

0 个答案:

没有答案