【问题标题】:How to create a simple C library using a header file如何使用头文件创建一个简单的 C 库
【发布时间】:2016-07-04 22:35:53
【问题描述】:

我在网上查过,无法完全正确地理解语法。我正在尝试创建一个头文件,以便可以在另一个 C 源文件中使用一个函数。该函数称为readLine(),它驻留在myown.c 中。我想在myown3.c中使用它。

这里是头文件myown.h

#define LINECAP 81
#ifndef MYOWN_H
#define MYOWN_H
void readLine ( char buffer [], LINECAP);
#endif

这里是myown.c

#include "myown.h"
#include <stdio.h>
void readLine ( char buffer [], int lineCapacity)   {
char  myCharacter;
  int i = 0 ;
  do {
    myCharacter = getchar();
    buffer[i] = myCharacter;
    i++;
  } while (myCharacter != '\n'  && i < lineCapacity );
  buffer [i-1] = '\0';
}

void cleanBuffer ( char buffer [])  {
  int i;
  for (i=0; i<81; i++)
    buffer[i] =0;
}

int main (int argc, char *argv[])   {
/* void readLine ( char buffer [], int lineCapactiy); */
void cleanBuffer(char buffer []);

  int i;
  char line[81];
  for (i=0; i<3; i++)  {
     //cleanBuffer(line);
     readLine(line,LINECAP);
     printf("%s", line);
     //cleanBuffer(line);
  }
}

这里是myown3.c,我想在里面使用函数:

#include "myown.h"
#include <stdio.h>
#include <stdbool.h>
bool alphabetic ( const char c) {
  //if ((c > 65 && c < 90)  || (c > 97 && c < 122))
  if (( c > 'a' && c < 'z') || ( c > 'A' && c < 'Z'))
     return true;
  else
     return false;
}

int countWords ( const char string[])    {
   int i, wordCount =0;
   bool lookingForWord= true, alphabetic (const char c);
   for ( i = 0; string[i] != '\0'; ++i) {
     if (alphabetic(string[i])) {
         wordCount++;
         lookingForWord = false;
     } else {
         lookingForWord = true;
     }
   }
  return wordCount;
}

int main (int argc, char *argv[])  {
  char text[81];
  int totalWords =0;
  int countWords ( const char string[]);
  /* void readLine (char buffer[], int lineCapacity); */
  bool endOfText = false;
  printf ("Type in your text.\n");
  printf ("Wehn you are done, press 'RETURN'.\n");
  while ( ! endOfText )    {
    readLine (text, 81);

    if ( text[0] == '\0')
      endOfText = true;
    else
    totalWords == countWords (text);
  }
  printf ("\nThere are %i words in the above text.\n", totalWords);
  return 0;
}

当我尝试编译时出现以下错误:

gcc -I. myown.c -o myown
In file included from myown.c:1:0:
myown.h:1:17: error: expected declaration specifiers or '...' before numeric constant
 #define LINECAP 81
                 ^
myown.h:4:33: note: in expansion of macro 'LINECAP'
 void readLine ( char buffer [], LINECAP);
                                 ^
make: *** [myown] Error 1

一切正常。我花了一些时间才弄清楚我必须分别编译和链接这些部分。当我尝试一次编译所有东西时出现以下错误:

$ gcc -I. myown3.c -o myown3
C:\Users\sansari\AppData\Local\Temp\ccYfmI6U.o:myown3.c:(.text+0xd1): undefined reference to `readLine'
collect2.exe: error: ld returned 1 exit status

但以下命令有效....

gcc myown.c -c -o myown.o
gcc myown3.c -c -o myown3.o
gcc myown3.o myown.o -o myown3

【问题讨论】:

  • readLine 的第二个参数应该是什么?
  • 附带说明,您可以使用标准库的东西来检查字母数字,例如isalnum(character)。查看ctype.h 了解更多信息。
  • 2 个通用 cmets,首先,您希望在头文件的包含保护中定义 #define。有助于避免重新声明的警告。其次,您在函数原型中使用了一个常量,这与您的函数定义不同。您可能想要更改原型以匹配(使用int)。

标签: c c-preprocessor header-files


【解决方案1】:

paulsm 几乎说对了:

#ifndef MYOWN_H
#define MYOWN_H

#define LINECAP 81

void readLine(char buffer[], int lineCapacity);

#endif

参数的类型必须在readLine()的原型中声明,而不是解析为81的某个常量。81不是有效的类型,也不是LINECAP.

由于myown.cmain()myown3.cmain() 冲突,您应该考虑将readLine() 的定义放在一个新文件中(例如mylib.c)并将其链接到myown.c 用于第一个程序,myown3.c 用于第二个程序。我也会将标题重命名为mylib.h

那么你有:

mylib.h:

#ifndef MYLIB_H
#define MYLIB_H

#define LINECAP 81

void readLine(char buffer[], int lineCapacity);

#endif

mylib.c:

#include "myown.h"
#include <stdio.h>
void readLine ( char buffer [], int lineCapacity)
{
  char myCharacter;
  int i = 0 ;
  do 
  {
    myCharacter = getchar();
    buffer[i] = myCharacter;
    i++;
  } while (myCharacter != '\n'  && i < lineCapacity );
  buffer [i-1] = '\0';
}

并且readLine()myown.c中删除

所以现在文件是:

  • mylib.cmylib.h(没有main()
  • 程序myown.c,包括mylib.h和链接到mylib.c
  • 程序myown3.c,包括mylib.h和链接到mylib.c

在你的代码中,你终于可以使用常量了:

readLine(text, LINECAP);

而不是

readLine(text, 81);

无论你在哪里使用81作为线路容量(例如cleanBuffer()),你都应该使用LINECAP,所以如果你想在一天内更改容量,你只需将值81更改为别的东西,只有一个地方 (mylib.h)。

我建议你在mylib.c 中也加入一些其他可重复使用的功能。

【讨论】:

  • 并在代码目前使用81的大部分地方使用LINECAP
  • 确实如此。这就是#defines 的用途,在一个地方定义这样的值,所以修改一个定义就足以在任何地方改变它。 @JonathanLeffler,你知道,但显然特立独行不知道。
【解决方案2】:

删除“void readLine()”的冗余原型;只需使用“myown.h”代替:

#ifndef MYOWN_H
#define MYOWN_H

#define LINECAP 81

void readLine ( char buffer [], int linecap);

#endif

主要问题:

  • 不要在原型中放置常量 (LINECAP)。

  • 在“myown.h”中,将include guard的“define* INSIDE

  • 您根本不需要多个原型:只需在“myown.h”中定义原型ONCE

  • 每个可执行文件必须有一个 - 并且只有一个 - “main()”。

  • #define LINECAP 81ONCE(在 myheader.h 中),并在其他任何地方使用 LINECAP(而不是“81”)。

【讨论】:

  • 你的意思是在标题中写:void readLine(char buffer[], int lineCapacity);
  • 在标头中,仅使用数据类型编写原型就足够了:void readLine (char [], int); 并将#define LINECAP 81 放入#include 保护#ifndef MYOWN_H ...
  • 两个文件都带有main() 不会链接。库有测试代码固然好,但需要条件编译。
  • @user3078414:是的,只写类型就足够了,但我喜欢包含参数名称的情况。我讨厌阅读不这样做的标题。这对编译器来说可能就足够了,但对于必须尝试理解代码的人来说就不够了。
  • @Rudy Velthuis - 我应该复制/粘贴整个程序,进行自己的测试构建,然后清除 ALL 错误。我更新了我的帖子-感谢您指出“myheader.h”原型中的错误!
猜你喜欢
  • 1970-01-01
  • 2011-04-06
  • 2013-03-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多