简体   繁体   English

头文件中声明函数的链接器混乱(C)

[英]Linker Confusion for Declared Functions in Header Files (C)

So I'm in a C programming class and I think of myself as an ok programmer, but I've come across something that I don't quite understand how to think through. 因此,我在C编程课程中,并且认为自己是个不错的程序员,但是我遇到了一些我不太了解如何思考的内容。 I'm writing a compressor that uses several header files and has two c files used for creating the executable. 我正在编写一个使用几个头文件的压缩程序,并使用两个c文件来创建可执行文件。 I've included the header files correctly (I think) by having them be in the same directory and saying 我已经正确地包含了头文件(我认为),方法是将它们放在同一目录中并说

#include "myLib.h"

Now. 现在。 Here's the part I'm stuck on. 这是我坚持的部分。 In one file I have a main method calling the functions declared in the header file. 在一个文件中,我有一个主要方法来调用在头文件中声明的函数。 The source code for these functions is in the other .c file I mentioned earlier. 这些功能的源代码在我前面提到的另一个.c文件中。 When I compile with: 当我编译时:

gcc -Wall TestCmp.c LZWCmp.o  

Where TestCmp.c is the file containing the main and LZWCmp.o is the object file for the other .c file. 其中TestCmp.c是包含main的文件,LZWCmp.o是另一个.c文件的目标文件。 I get compile errors telling me that three of the the four declared methods are undefined references. 我收到编译错误,告诉我四个已声明方法中的三个是未定义的引用。 Why would the linker accept that one of these methods exists but not the other three??? 链接器为什么会接受这些方法之一存在而其他三种不存在?

Any help would be appreciated. 任何帮助,将不胜感激。 Thanks! 谢谢!

Here's the source code for TestCmp.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*/

}

And the source code for myLib.h 以及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

and the source for LZWCmp.h 以及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

As for the object I'm compiling with, it is an .o file given to us by the professor containing the four functions given in LZWCmp.h file. 至于我正在编译的对象,这是教授给我们的.o文件,其中包含LZWCmp.h文件中给出的四个功能。 If our TestCmp.c file works correctly, than I should be able to access the functions inside of the LZCmp.o file without a problem. 如果我们的TestCmp.c文件可以正常工作,那么我应该可以毫无问题地访问LZCmp.o文件内部的功能。

OK.. with few modification to your code, I was able to (link and) compile your code.. The files are as follows: OK ..只需对您的代码进行少量修改,我就可以(链接和)编译您的代码。.文件如下:

Filename: TestCmp.c 档名: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;

}

Filename: MyLib.h 档名: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

Filename: LZWCmp.h 档名: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

Filename: LZWCmp.c (this is what I've introduced which will be passed to the make command - see below) 文件名: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");    
}

Make command: 发出命令:

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

Hope this helps! 希望这可以帮助!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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