【问题标题】:Linker Confusion for Declared Functions in Header Files (C)头文件中声明函数的链接器混淆 (C)
【发布时间】:2012-04-24 18:05:56
【问题描述】:

所以我在上 C 编程课程,我认为自己是一名优秀的程序员,但我遇到了一些我不太明白如何思考的事情。我正在编写一个使用多个头文件并有两个用于创建可执行文件的 c 文件的压缩器。我已经正确地包含了头文件(我认为),将它们放在同一个目录中并说

#include "myLib.h"

现在。这是我坚持的部分。在一个文件中,我有一个调用头文件中声明的函数的主要方法。这些函数的源代码在我之前提到的另一个 .c 文件中。当我编译时:

gcc -Wall TestCmp.c LZWCmp.o  

其中 TestCmp.c 是包含主文件的文件,LZWCmp.o 是另一个 .c 文件的目标文件。 我收到编译错误,告诉我四个声明的方法中的三个是未定义的引用。为什么链接器会接受其中一种方法存在而其他三种不存在???

任何帮助将不胜感激。谢谢!

这是 TestCmp.c 的源代码

#include <stdio.h>
#include <assert.h>
#include <limits.h>
#include "LZWCmp.h"
#include "SmartAlloc.h"
#include "MyLib.h"

/*function pointer to the CodeSink function in TestCmp, which function simply prints  each 4-byte uint sent to it as 8 hex digits. It does so 8 integers per line, with one space between each pair of integers, and no space after the final integer, just an EOL.*/
void sink(void *pointer, uint code) {
    printf("%08X ", code);
}

void main() {
   int numCodes; /*Number of codes that compressor starts with understanding*/
   LZWCmp *cmp = malloc(sizeof(struct LZWCmp)); /*allocate memory for compressor state*/
   CodeSink ptr = sink; /*set sodesink pointer to sink function*/
   uchar letter; /*letter for intake and compression*/

   printf("Enter symbol count: ");
   scanf(" %d", &numCodes);
   while(letter != '\n') {
      letter = getchar();
   }

   LZWCmpInit(cmp, numCodes, ptr, NULL); /*Initialize compressor */

   while(letter < UCHAR_MAX) {
      letter = getchar(); 
      LZWCmpEncode(cmp, letter);     /*Send letter to encoder*/ /*FIRST FUNCTION TO NOT WORK*/
   }

   LZWCmpStop(cmp); /*Finish program when finding EOF character*/
   LZWCmpDestruct(cmp); /*Free memory space*/

}

还有 myLib.h 的源代码

#ifndef MYLIB_H
#define MYLIB_H

#define BITS_PER_BYTE 8

typedef unsigned char uchar;
typedef unsigned long ulong;
typedef unsigned int uint;
typedef unsigned short ushort;

#ifdef LITTLE_ENDIAN

#define UShortEndianXfer(val) ((val) >> 8 | (val) << 8}

#else

#define UShortEndianXfer(val) (val)

#endif

#endif

以及 LZWCmp.h 的来源

#ifndef LZW_H
#define LZW_H

#include "MyLib.h"

#define RECYCLE_CODE 4096  // Recycle dictionary rather than add this code

/* Function pointer to method to call when a code is completed and ready for
 * transmission or whatever.  The void * parameter can point to anything,
 * and gives hidden information to the function so that it can know what
 * file, socket, etc. the code is going to.  The uint is the next 32 bits
 * worth of compressed output. */
typedef void (*CodeSink)(void *, uint code);

/* One node in a trie representing the current dictionary.  Use symbols
 * to traverse the trie until reaching a point where the link for a
 * symbol is null.  Use the code for the prior link, and add a new code in
 * this case.  Each node has as many links and codes as there are symbols */
typedef struct TrieNode {
    ushort *codes;
    struct TrieNode **links;
} TrieNode;

/* Current state of the LZW compressor. */
typedef struct LZWCmp {
   TrieNode *head;   /* Head pointer to first TrieNode */
   CodeSink sink;   /* Code sink to send bits to */
   void *sinkState;  /* Unknown object to send to sink for state */
   int numSyms;      /* Symbol count, also size of TrieNodes */
   int nextCode;     /* Next code to be assigned */
   int numBits;      /* Number of bits per code currently */
   uint nextInt;     /* Partially-assembled next int of output */
   int bitsUsed;     /* Number of valid bits in top portion of nextInt */
   TrieNode *curLoc; /* Current position in trie */
   short lastSym;    /* Most recent symbol encoded */
} LZWCmp;

/* Initialize a LZWCmp given the number of symbols and the CodeSink
 * to which to send completed codes; */
void LZWCmpInit(LZWCmp *cmp, int numSyms, CodeSink sink, void *sinkState);

/* Encode "sym" using LZWCmp. Zero or more calls of the code sink
 * may result */
 void LZWCmpEncode(LZWCmp *cmp, uchar sym);

/* Mark end of encoding (send next code value to code sink) */
void LZWCmpStop(LZWCmp *cmp);

/* Free all storage associated with LZWCmp (not the sinkState, though,
 * which is "owned" by the caller */
void LZWCmpDestruct(LZWCmp *cmp);

#endif

至于我正在编译的对象,它是教授给我们的一个.o文件,其中包含LZWCmp.h文件中给出的四个函数。如果我们的 TestCmp.c 文件正常工作,那么我应该能够毫无问题地访问 LZCmp.o 文件中的函数。

【问题讨论】:

  • 这还不足以诊断问题,您是如何编译LZWCmp 的?源代码看起来如何?
  • @DanielFischer 我们应该如何编译 .h 文件来创建目标文件?!
  • @SangeethSaravanaraj 这是另一个.c 文件。
  • “myLib.h”的内容是什么?它们应该具有您将要从其他 .c 文件中使用的函数的声明。请在此处放置指向您代码的 pastebin 链接,以便我们更好地了解。我们在这里在黑暗中摸索。
  • 请发布实际的错误信息。另外,发布来自nm LZWCmp.o | grep LZWCmp 的输出。这些信息将让我们看到链接器正在寻找什么以及.o 文件中的实际内容。

标签: c linker-errors header-files


【解决方案1】:

好的.. 只需对您的代码进行少量修改,我就能够(链接和)编译您的代码.. 文件如下:

文件名:TestCmp.c

#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <limits.h>
#include "LZWCmp.h"
//#include "SmartAlloc.h"
#include "MyLib.h"

/*function pointer to the CodeSink function in TestCmp, which function simply prints  each 4-byte uint sent to it as 8 hex digits. It does so 8 integers per line, with one space between each pair of integers, and no space after the final integer, just an EOL.*/
void sink(void *pointer, uint code) {
    printf("%08X ", code);
}

int main(void) 
{
   int numCodes; /*Number of codes that compressor starts with understanding*/
   LZWCmp *cmp = malloc(sizeof(struct LZWCmp)); /*allocate memory for compressor state*/
   CodeSink ptr = sink; /*set sodesink pointer to sink function*/
   uchar letter; /*letter for intake and compression*/

   printf("Enter symbol count: ");
   scanf(" %d", &numCodes);
   while(letter != '\n') {
      letter = getchar();
   }

   LZWCmpInit(cmp, numCodes, ptr, NULL); /*Initialize compressor */

   while(letter < UCHAR_MAX) {
      letter = getchar(); 
      LZWCmpEncode(cmp, letter);     /*Send letter to encoder*/ /*FIRST FUNCTION TO NOT WORK*/
   }

   LZWCmpStop(cmp); /*Finish program when finding EOF character*/
   LZWCmpDestruct(cmp); /*Free memory space*/

    return 0;

}

文件名:MyLib.h

#ifndef MYLIB_H
#define MYLIB_H

#define BITS_PER_BYTE 8

typedef unsigned char uchar;
typedef unsigned long ulong;
typedef unsigned int uint;
typedef unsigned short ushort;

#ifdef LITTLE_ENDIAN

#define UShortEndianXfer(val) ((val) >> 8 | (val) << 8}

#else

#define UShortEndianXfer(val) (val)

#endif

#endif

文件名:LZWCmp.h

#ifndef LZW_H
#define LZW_H
#include <stdio.h>
#include "MyLib.h"

#define RECYCLE_CODE 4096  // Recycle dictionary rather than add this code

/* Function pointer to method to call when a code is completed and ready for
 * transmission or whatever.  The void * parameter can point to anything,
 * and gives hidden information to the function so that it can know what
 * file, socket, etc. the code is going to.  The uint is the next 32 bits
 * worth of compressed output. */
typedef void (*CodeSink)(void *, uint code);

/* One node in a trie representing the current dictionary.  Use symbols
 * to traverse the trie until reaching a point where the link for a
 * symbol is null.  Use the code for the prior link, and add a new code in
 * this case.  Each node has as many links and codes as there are symbols */
typedef struct TrieNode {
    ushort *codes;
    struct TrieNode **links;
} TrieNode;

/* Current state of the LZW compressor. */
typedef struct LZWCmp {
   TrieNode *head;   /* Head pointer to first TrieNode */
   CodeSink sink;   /* Code sink to send bits to */
   void *sinkState;  /* Unknown object to send to sink for state */
   int numSyms;      /* Symbol count, also size of TrieNodes */
   int nextCode;     /* Next code to be assigned */
   int numBits;      /* Number of bits per code currently */
   uint nextInt;     /* Partially-assembled next int of output */
   int bitsUsed;     /* Number of valid bits in top portion of nextInt */
   TrieNode *curLoc; /* Current position in trie */
   short lastSym;    /* Most recent symbol encoded */
} LZWCmp;

/* Initialize a LZWCmp given the number of symbols and the CodeSink
 * to which to send completed codes; */
void LZWCmpInit(LZWCmp *cmp, int numSyms, CodeSink sink, void *sinkState);

/* Encode "sym" using LZWCmp. Zero or more calls of the code sink
 * may result */
 void LZWCmpEncode(LZWCmp *cmp, uchar sym);

/* Mark end of encoding (send next code value to code sink) */
void LZWCmpStop(LZWCmp *cmp);

/* Free all storage associated with LZWCmp (not the sinkState, though,
 * which is "owned" by the caller */
void LZWCmpDestruct(LZWCmp *cmp);

#endif

文件名:LZWCmp.c(这是我介绍的,将传递给 make 命令 - 见下文)

#include "LZWCmp.h"

void LZWCmpInit(LZWCmp *cmp, int numSyms, CodeSink sink, void *sinkState)
{
    printf("LZWCmpInit \n");
}

void LZWCmpEncode(LZWCmp *cmp, uchar sym)
{
    printf("LZWCmpEncode \n");   
}

void LZWCmpStop(LZWCmp *cmp)
{
    printf("LZWCmpStop \n");
}

void LZWCmpDestruct(LZWCmp *cmp)
{
    printf("LZWCmpDestruct \n");    
}

制作命令:

gcc -Wall TestCmp.c LZWCmp.h MyLib.h LZWCmp.c

希望这会有所帮助!

【讨论】:

  • 您能突出显示您所做的更改吗?
  • @MIkhail 我已经为LZWCmp.c 添加了一个存根,在TestCmp.c 中评论了#include "SmartAlloc.h",因为我们没有,添加#include &lt;stdio.h&gt;LZWCmp.hprintf's ,并且MyLib.h 没有变化。并且在gcc 命令中,我已经传递了所需的文件。
  • 你能解释一下它是如何解决的吗?我了解您将 .h 文件添加到编译器中,但我真的不明白如何修复我遇到的错误。是因为您明确告诉链接器使用这些添加的文件进行编译吗?
猜你喜欢
  • 2022-01-13
  • 1970-01-01
  • 1970-01-01
  • 2010-11-24
  • 1970-01-01
  • 2018-12-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多