C语言标准库函数原型设计

hijack00 2016-09-05 09:37:55
最近试着自己实现一些C库中的函数,于是参考了标准库(我用的是mingw)头文件中的函数声明,发现自己对标准库中函数原型设计存在一些不解的地方。
例如,在string.h中,有如下声明:
1. char* strchr(const char*, int);
该函数是在一个字符串中查找字符首次出现的位置,那么第二个参数为什么是int类型而不是char类型?
2. void* memset(void*, int, size_t);
memset是逐字节操作的,理论上第二个参数设为char类型就足够了,那么函数第二个参数为什么要设置为int类型?

库作者的基本考虑是什么?
...全文
908 29 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
29 条回复
切换为时间正序
请发表友善的回复…
发表回复
lm_whales 2016-09-08
  • 打赏
  • 举报
回复
其实当初,FFFF也就是EOF(-1) 本来就是文件结束标志。 文本文件写入FFFF,表示文件结束。 读文件的时候,读到FFFF表示文件结束了。 所以 getc,getchar 返回 -1 表示文件结束 而 控制台 用^Z或者^D ,表示文件输入结束,只是一个方便的法子
hijack00 2016-09-06
  • 打赏
  • 举报
回复
引用 17 楼 paschen 的回复:
[quote=引用 13 楼 hijack00的回复:][quote=引用 11 楼 paschen 的回复:] 历史原因,putchar 等一系列函数参数类型都是int
部分认同是历史原因,但还是坚持认为可能有技术层面的考虑。毕竟库的设计者都是大牛,不可能是随随便便就决定了的[/quote] 读下这个: http://wenku.baidu.com/link?url=1jdn5PU6EurW8Sqpx3VubBJZsTC2OLUWeHCbWq6VEfRahnlYb1XcSKhta-cBnlv9uvAGjPyzbWB38wVxNfcYyw8gtFqGD4cYHNWMwC0sOTG[/quote] 浏览了一下这篇文章,但是其权威性还有待证实。 文中提到 (c = fgetc(fp)) != EOF /* 读到值为FF的字符,误认为 EOF */ 按我的理解,fgetc应该是读不到值为FF的字符的。fgetc要么返回一个ASCII字符(这里不考虑读取中文字符的情况),要么是EOF,这样EOF就表示文件末尾或者输入结束。 要想读入类似FF这样的值,我认为应该要用二进制模式打开文件,并且用fread这样的函数来读取文件内容,这样才能将文件内容按照字节进行读取。 而fscanf,fpritnf,fgetc,fputc这一类的函数应该是用于读写文本文件的。
lm_whales 2016-09-06
  • 打赏
  • 举报
回复
其实,数学运算,大部分,统一为 int,double 是为了编译器,实现的方便 这样,库代码的实现,也简单方便。 同样,参数传递也是一样 为了编译器实现的方便。
paschen 2016-09-06
  • 打赏
  • 举报
回复
引用 13 楼 hijack00的回复:
[quote=引用 11 楼 paschen 的回复:] 历史原因,putchar 等一系列函数参数类型都是int
部分认同是历史原因,但还是坚持认为可能有技术层面的考虑。毕竟库的设计者都是大牛,不可能是随随便便就决定了的[/quote] 读下这个: http://wenku.baidu.com/link?url=1jdn5PU6EurW8Sqpx3VubBJZsTC2OLUWeHCbWq6VEfRahnlYb1XcSKhta-cBnlv9uvAGjPyzbWB38wVxNfcYyw8gtFqGD4cYHNWMwC0sOTG
lm_whales 2016-09-06
  • 打赏
  • 举报
回复
double 类型早就有了,因为fortran 就有 real (对应 float),double 两种不同精度的浮点数了, fortran 是最早的高级语言了 因为当时 double 精度够用了 float 精度不太够用 所以,doule 就作为 浮点类型的代表了 所以标注库的数学函数,都是 double 类型的 至于浮点数协处理器,那是根据 以前浮点数的使用情况,制造出来的 不是因为有了浮点处理器,才有float,double 的 也许 long double 跟浮点处理器有点关系。 float ,double 是早就存在的 浮点数,曾经有个,48Bits 浮点数,这是 pascal最初,常用浮点类型。
www_adintr_com 2016-09-06
  • 打赏
  • 举报
回复
有瑕疵也不必回避, 更不用为他披上神圣的光环. 站在现在的观点看过去很多有不完善的地方, 并不代表你回到过去就能做得更好.
pengzhixi 2016-09-06
  • 打赏
  • 举报
回复
特意下了c程序设计语言 可以去看看A.7.3.2 Function Calls 这一节内容。里面讲了这些
hijack00 2016-09-06
  • 打赏
  • 举报
回复
引用 11 楼 paschen 的回复:
历史原因,putchar 等一系列函数参数类型都是int
部分认同是历史原因,但还是坚持认为可能有技术层面的考虑。毕竟库的设计者都是大牛,不可能是随随便便就决定了的
www_adintr_com 2016-09-06
  • 打赏
  • 举报
回复
引用 3 楼 pengzhixi 的回复:
你看下EOF的值是-1,你觉得char不能表示么?这方面我觉得更是为了统一。内存对齐这个有点扯了。你传参是从char传过去的,那这个char在哪?不还是在内存么?那么你觉得这个char会对齐么?所以就只是一个算术转换做类型提升而已。而且对齐这个在不同体系结构下标准都不一样。没办法统一的。
EOF 的 -1 和 char 的 -1 是不同的. 如果用 char 的 -1 0xFF 来表示 EOF, 当你读取一个二进制文件时, 难道遇到文件里面的 0XFF 就代表文件结束了? 要表示 EOF 必须用 char 的值范围外的值才行.
paschen 2016-09-06
  • 打赏
  • 举报
回复
历史原因,putchar 等一系列函数参数类型都是int
fefe82 2016-09-06
  • 打赏
  • 举报
回复
引用 9 楼 pengzhixi 的回复:
[quote=引用 8 楼 fefe82 的回复:] [quote=引用 5 楼 pengzhixi 的回复:] 那float提升为double呢?你总不能也说是内存对齐吧。
应该是为了精度吧。 而且,计算及的浮点运算器通常只能处理某一种特定类型的浮点数,一般是 double 或者一种更长的浮点类型。所以在计算的时候,基本还是要转换的。[/quote]现在是可以说为了提高精度和表示范围。但是k&r那个时候应该不是。那个时候是否有专门的浮点运算单元都不一定。所以那个时候应该还说不上为了提高精度。[/quote] K&R 的时代,C 是没有标准的。K&R 的 The C programming language 是 1978 年出版的,实际是当时 K&R C 的事实标准。 然后刚刚去翻了一下,浮点单元 8087 出现是在 1980 年,IEEE-754 成文是在 1985 年(8087是在IEEE 754 草案阶段实现的),C 的第一版标准是在 1989 年。 在 C&R C 2nd Edition (1988年) 里找到这样一段话: Notice that floats in an expression are not automatically converted to double; this is a change fro the original definition. In general, mathematical functions like those in <math.h> will use double precision. The main reason for using float is to save storage in large arrays, or less often, to save time on machines where double-precision arithmetic is particularly expensive. 所以,当时跟现在还是有很多不一样的。
pengzhixi 2016-09-06
  • 打赏
  • 举报
回复
引用 8 楼 fefe82 的回复:
[quote=引用 5 楼 pengzhixi 的回复:] 那float提升为double呢?你总不能也说是内存对齐吧。
应该是为了精度吧。 而且,计算及的浮点运算器通常只能处理某一种特定类型的浮点数,一般是 double 或者一种更长的浮点类型。所以在计算的时候,基本还是要转换的。[/quote]现在是可以说为了提高精度和表示范围。但是k&r那个时候应该不是。那个时候是否有专门的浮点运算单元都不一定。所以那个时候应该还说不上为了提高精度。
fefe82 2016-09-06
  • 打赏
  • 举报
回复
引用 5 楼 pengzhixi 的回复:
那float提升为double呢?你总不能也说是内存对齐吧。
应该是为了精度吧。 而且,计算及的浮点运算器通常只能处理某一种特定类型的浮点数,一般是 double 或者一种更长的浮点类型。所以在计算的时候,基本还是要转换的。
pengzhixi 2016-09-06
  • 打赏
  • 举报
回复
额 类型提升带来的好处就像你说的 可能在某些体系结构上是处于对齐的。访问和操作都会十分高效。至于通过寄存器传参的就不管了。效率怎么都不会太差。
hijack00 2016-09-06
  • 打赏
  • 举报
回复
引用 5 楼 pengzhixi 的回复:
那float提升为double呢?你总不能也说是内存对齐吧。
我只是以一种不太严谨的说法表达了与你类似的意思。我已经说了我那个说法不严谨了。而且对于ARM直接将参数复制到寄存器的做法,甚至都不涉及到内存。此外,你说的float提升为double类型,或者更复杂的情况(例如实参是结构体等等复合类型)我也考虑到了,所以我上面说的是“大部分都是4字节对齐”,这包括(char,short,int,指针)等等情况。如果真的要钻牛角尖的话,在64位系统上,有可能大部分情况下就是8字节对齐了(我对64位系统了解不多,如果说错了,当我没说)
pengzhixi 2016-09-06
  • 打赏
  • 举报
回复
那float提升为double呢?你总不能也说是内存对齐吧。
hijack00 2016-09-06
  • 打赏
  • 举报
回复
引用 3 楼 pengzhixi 的回复:
你看下EOF的值是-1,你觉得char不能表示么?这方面我觉得更是为了统一。内存对齐这个有点扯了。你传参是从char传过去的,那这个char在哪?不还是在内存么?那么你觉得这个char会对齐么?所以就只是一个算术转换做类型提升而已。而且对齐这个在不同体系结构下标准都不一样。没办法统一的。
1.(早期)正常的char的类型只有0-127是代表ASCII字符的,最高位固定为0。我是从这个角度去说的,从C语言规范来说,char类型自然是可以表示-1。 2. 我关于内存对齐的说法并不严谨。C语言参数传递在不同体系架构下应该是有区别的,例如,在PC平台下看C语言函数的汇编代码,参数好像都是直接入栈的,而且大部分都是4字节对齐(esp+4,esp+8)。而以前看ARM的时候,好像是说参数比较少的时候直接复制到通用寄存器(两年多没碰了,不知道记得准不准确) 3. 我上面说的内存对齐和你的类型提升其实表达的是差不多的意思。我想表达的意思是:当参数入栈的时候,char类型的实参只有一个字节,通过将其转换为一个int类型再入栈,从而也是4字节,这样就可以对齐了。
pengzhixi 2016-09-06
  • 打赏
  • 举报
回复
你看下EOF的值是-1,你觉得char不能表示么?这方面我觉得更是为了统一。内存对齐这个有点扯了。你传参是从char传过去的,那这个char在哪?不还是在内存么?那么你觉得这个char会对齐么?所以就只是一个算术转换做类型提升而已。而且对齐这个在不同体系结构下标准都不一样。没办法统一的。
hijack00 2016-09-06
  • 打赏
  • 举报
回复
引用 1 楼 pengzhixi 的回复:
好吧,这个是一个历史原因造成的。因为在k&R那个时期,也就是远古时代。函数的声明是这样的。 char* strchr(); 然后定义函数是这样 char*strchr(s,c) char*s; char c; { ... } 你可以看到函数声明是没有参数之类的,不像现在的函数原型 需要有参数类型等信息。这样在传递参数的时候会有个算术转换(现在叫类型提升之类的)就是说凡是比int小的类型 比如char,short传进去之后全部提升为int类型。然后你看到定义里面有char c 这样 又从int转型为char 在函数体里面使用。所以估计后面干脆把类型声明为int也是提醒别人 这里会有个算术转换吧。
标准库中有些函数原型设计是设计者别有用心的,例如getchar返回int而不是char,是为了考虑EOF的情况;再如strcpy等函数返回一个指针是为了实现链式调用,等等。所以我比较好奇除了历史原因,库作者有没有技术上的考虑 另外,你的提醒调用者注意类型转换的说法我也表示同意,即使是char类型,在调用函数时,参数入栈的过程中char类型的实参应该也是存入一个32位寄存器(32位机器上)的,所以声明为int类型可能是出于内存对齐以及容错上的考虑。
pengzhixi 2016-09-06
  • 打赏
  • 举报
回复
引用 25 楼 oN5GrzoN 的回复:
[quote=引用 1 楼 pengzhixi 的回复:] 好吧,这个是一个历史原因造成的。因为在k&R那个时期,也就是远古时代。函数的声明是这样的。 char* strchr(); 然后定义函数是这样 char*strchr(s,c) char*s; char c; { ... } 你可以看到函数声明是没有参数之类的,不像现在的函数原型 需要有参数类型等信息。这样在传递参数的时候会有个算术转换(现在叫类型提升之类的)就是说凡是比int小的类型 比如char,short传进去之后全部提升为int类型。然后你看到定义里面有char c 这样 又从int转型为char 在函数体里面使用。所以估计后面干脆把类型声明为int也是提醒别人 这里会有个算术转换吧。
翻译的不错呀 http://stackoverflow.com/questions/2394011/why-does-strchr-take-an-int-for-the-char-to-be-found[/quote]是的 照搬上面的。
加载更多回复(9)

70,020

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧