Путаница компоновщика для объявленных функций в заголовочных файлах (C)
Так что я нахожусь в классе программирования на C и считаю себя хорошим программистом, но я наткнулся на то, что не совсем понимаю, как продумывать. Я пишу компрессор, который использует несколько заголовочных файлов и имеет два файла c, используемых для создания исполняемого файла. Я включил заголовочные файлы правильно (я думаю), поместив их в один каталог и сказав
#include "myLib.h"
Сейчас. Вот часть, на которой я застрял. В одном файле у меня есть метод main, вызывающий функции, объявленные в заголовочном файле. Исходный код для этих функций находится в другом.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.
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
Надеюсь это поможет!