简体   繁体   中英

C: Dereferencing pointer to incomplete type error

The project I am trying to compile on OS X is: https://github.com/Ramblurr/PietCreator

Am unfortunately unable to fix the problems with the following lines:

width = info_ptr->width;
height = info_ptr->height;
ncol = 2 << (info_ptr->bit_depth - 1);

Which produce the errors:

file.c: In function ‘read_png’:
file.c:1117: error: dereferencing pointer to incomplete type
file.c:1118: error: dereferencing pointer to incomplete type
file.c:1119: error: dereferencing pointer to incomplete type

Full code of the read_png function below:

#include <png.h>
#include <math.h>

png_byte bit_depth;

png_structp png_ptr;
png_infop info_ptr;
int number_of_passes;
png_bytep * row_pointers;


int
read_png (char *fname)
{
  char header [8];

  FILE *in;
  int i, j, ncol, rc;

  if (! strcmp (fname, "-")) {
    /* read from stdin: */
    vprintf ("info: not trying to read png from stdin\n");
    return -1;
  }

  if (! (in = fopen (fname, "rb"))) { 
    fprintf (stderr, "cannot open `%s'; reason: %s\n", fname,
         strerror (errno));
    return -1;
  }

  if (! in || (rc = fread (header, 1, 8, in)) != 8
      || png_sig_cmp ((unsigned char *) header, 0, 8) != 0) {
    return -1;
  }

  if (! (png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, 0, 0, 0))
      || ! (info_ptr = png_create_info_struct (png_ptr))) {
    return -1;
  }

  png_init_io (png_ptr, in);
  png_set_sig_bytes (png_ptr, 8);

  png_read_png (png_ptr, info_ptr, 
        PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_STRIP_ALPHA
        | PNG_TRANSFORM_EXPAND, NULL);
  /**       | PNG_TRANSFORM_PACKING | PNG_TRANSFORM_SHIFT **/

  row_pointers = png_get_rows (png_ptr, info_ptr);

  width = info_ptr->width;
  height = info_ptr->height;
  ncol = 2 << (info_ptr->bit_depth - 1);

  vprintf ("info: got %d x %d pixel with %d cols\n", width, height, ncol);

  alloc_cells (width, height);

  for (j = 0; j < height; j++) {
    png_byte *row = row_pointers [j];
    for (i = 0; i < width; i++) {

      png_byte *ptr = & row [i * 3];

      /* ncol always 256 ? */
      int r = (ptr [0] * 256) / ncol;
      int g = (ptr [1] * 256) / ncol;
      int b = (ptr [2] * 256) / ncol;

      int col = ((r * 256 + g) * 256) + b;
      int col_idx = get_color_idx (col);

      if (col_idx < 0) {
    if (unknown_color == -1) {
      fprintf (stderr, "cannot read from `%s'; reason: invalid color found\n",
           fname);
      return -1;
    } else {
      /* set to black or white: */
      col_idx = (unknown_color == 0 ? c_black : c_white);
    }
      }

      set_cell (i, j, col_idx);
    }
  }

  return 0;
}

I think it is by design of the creator of png.h module.

It should be that png_infop is declared as a pointer to a struct in "png.h" . The actual struct declaration and definition should be in "png.c" .

The author does not want to expose the internals of the struct so the struct is defined in the "png.c" .

This means you cannot access any member of the struct (ie: info_ptr->width , info_ptr->height , info_ptr->bit_depth .

The struct members are not meant to be accessed by user.

I bet there are functions to access those members if the author thinks that you will need the width , height , or bit_depth information (ie: getWidth(info_ptr) , getHeight(info_ptr) , ...).

You need to look in png.h (or its documentation), find out what the type png_infop is a pointer to, and then find out how you're supposed to access its fields. Assuming that this pointer is really the right thing to get that data from, then either you need to include the definition of that type (so that the compiler knows about its data members width etc) from some other header, or else there are getter functions you're supposed to call that take a png_infop parameter and return the info you're after.

[Edit: looks as if you're supposed to use png_get_IHDR , or png_get_image_width etc.]

I compiled the project on Mac OS X 10.6.8 successfully.

git clone https://github.com/Ramblurr/PietCreator.git   
cd PietCreator
mkdir build
cd build
cmake ../

-- The C compiler identification is GNU
-- The CXX compiler identification is GNU
-- Checking whether C compiler has -isysroot
-- Checking whether C compiler has -isysroot - yes
-- Checking whether C compiler supports OSX deployment target flag
-- Checking whether C compiler supports OSX deployment target flag - yes
-- Check for working C compiler: /usr/bin/gcc
-- Check for working C compiler: /usr/bin/gcc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Checking whether CXX compiler has -isysroot
-- Checking whether CXX compiler has -isysroot - yes
-- Checking whether CXX compiler supports OSX deployment target flag
-- Checking whether CXX compiler supports OSX deployment target flag - yes
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Looking for Q_WS_X11
-- Looking for Q_WS_X11 - not found.
-- Looking for Q_WS_WIN
-- Looking for Q_WS_WIN - not found.
-- Looking for Q_WS_QWS
-- Looking for Q_WS_QWS - not found.
-- Looking for Q_WS_MAC
-- Looking for Q_WS_MAC - found
-- Looking for QT_MAC_USE_COCOA
-- Looking for QT_MAC_USE_COCOA - found
-- Found Qt-Version 4.7.4 (using /usr/local/bin/qmake)
-- Looking for gdImagePng in /usr/local/lib/libgd.dylib
-- Looking for gdImagePng in /usr/local/lib/libgd.dylib - found
-- Found ZLIB: /usr/include (found version "1.2.3")
-- Found PNG: /usr/X11R6/lib/libpng.dylib 
-- Looking for gdImageJpeg in /usr/local/lib/libgd.dylib
-- Looking for gdImageJpeg in /usr/local/lib/libgd.dylib - found
-- Found JPEG: /usr/local/lib/libjpeg.dylib 
-- Looking for gdImageGif in /usr/local/lib/libgd.dylib
-- Looking for gdImageGif in /usr/local/lib/libgd.dylib - found
-- Found GD: /usr/local/lib/libgd.dylib
-- Found GIF: /usr/local/lib/libgif.dylib 
-- Looking for include files HAVE_GD_H
-- Looking for include files HAVE_GD_H - found
-- Looking for include files HAVE_PNG_H
-- Looking for include files HAVE_PNG_H - not found.
-- Looking for include files HAVE_GIF_LIB_H
-- Looking for include files HAVE_GIF_LIB_H - found
-- Configuring done
-- Generating done
-- Build files have been written to: /Developer/workspace/png/PietCreator/build

After running make the application was compiled successfully:

Linking CXX executable pietcreator
[ 95%] Built target pietcreator
[ 97%] Generating NPietTest.moc
Scanning dependencies of target npiettest
[100%] Building CXX object npiet/CMakeFiles/npiettest.dir/test/NPietTest.cpp.o
Linking CXX executable npiettest
[100%] Built target npiettest

The only problems I ran into were all related to missing dependencies when executing cmake ../ . I had to download/compile/install Qt 4.7.4 and Qt-mobility 1.2.0 . After that, I also needed libgd and giflib but then I used brew for the job.

I suggest you try another git clone and try to compile it again from scratch.

If you would like to know, brew installed gd 2.0.36RC1 and giflib 4.1.6 .

You usually get this error when you have a forward declaration in the header and you don't include the file for the corresponding class in the source file:

//header.h
class B;
class A{
A();
B* b;
}

//source.cpp
#include "header.h"
//include "B.h" //include header where B is defined to prevent error
A::A()
{
   b->foo(); //error, B is only a forward declaration
}

Therefore, you need to include the appropriate header, a forward declaration is not enough.

incomplete reference errors typically occur when you have a construct as under:

struct foo;

int bar(void) {
     struct foo *p;
     p->a = 0;
}

here The foo struct is declared however its actual content is not known, And will yield a dereferencing to an incomplete type error.

The philosophy behind this is to force a formal API usage to manipulate data structures. this ensures that future API can change the structure much more easily without affecting legacy programs.

So typically an API header will do something like this:

/*
 * foo.h part of foo API 
 */

struct foo;

extern void foo_set_a(struct foo *p, int value);
extern int foo_get_a(struct foo *p);

It will internally implement the foo API functions ... for instance:

/* 
 * foo.c ... implements foo API 
 */

struct foo {
   int a;
};

void foo_set_a(struct foo *p, int value) {
    p->a = value;
}

int foo_get_a(struct foo *p) {
    return p->a;
}

and then the user of foo API can:

use_foo() {
    struct foo *my_foo;
    foo_set_a(my_foo, 1);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM