为什么 fputs() 需要一个常量作为第一个参数而不是 fputc()?

Why does fputs() require a constant as first parameter and not fputc()?

int fputc(int c, FILE *stream);

int fputs(const char *s, FILE *stream);

为什么 fputc() 的声明中不需要 const int c

第一个参数不用做const; "top level" 个参数被复制,而不是被引用,所以 const 要做的就是防止被调用函数修改它自己的参数副本。

同样,请注意只有指向的值是 const for fputs;该参数不是 const char *const s 因为额外的 const-ness 只会限制被调用者修改其指针副本指向的位置的能力; const 保证仅适用于指向的(共享)值。

在函数声明中将参数标记为 const 没有意义。参数按值传递,因此参数无论如何都是一个副本。它不影响函数的调用方式。

但是,const char *s不代表s就是const。这个声明的意思是 s 是一个指向 const char 的指针;即 fputs 函数承诺不会通过给定的指针进行写入。此外,还有从 char *const char * 的隐式转换(反之亦然),这意味着 fputs 可以用只读和可写字符串调用。

const修饰符防止函数改变输入参数。

fputc 函数使用 int c 作为值类型的输入。因为参数是按值传递的,函数只能改变内部副本,不能改变原来的值。

fputs函数使用char *s作为指针类型的输入,所以指向的内存可以被函数改变。 const 修饰符通过防止函数更改它来保护指向的内存。

注1:函数fputs中的const修饰符在char类型(const char *s)上,即表示无法更改指向的内存。如果 const 在输入参数 s (char * const s) 上,它不会保护指向的内存,它只会保护无论如何按值传递的指针本身。

注2:Eric Postpischil in the comment and shown in Vlad from Moscow's 所述,如果const修饰符在函数声明中而不是在函数定义中,则没有作用。

const char *s 并不意味着 s 必须指向一个常量。这意味着 fputs 不允许修改 s.

指向的内容

当编译器确定函数类型时,高级参数限定符将被丢弃。

所以这两个函数声明

int fputc(int c, FILE *stream);
int fputc( const int c, FILE *stream);

声明同一个函数。

以及这两个函数声明

int fputs(const char *s, FILE *stream);
int fputs(const char * const s, FILE *stream);

同样声明一个函数。

因此高级限定符const 对函数的用户没有意义,只对函数的内部定义有意义。在任何情况下,相应的参数都是按值传递的,即函数处理参数的副本。因此,对于函数的用户而言,副本是否在函数内部具有限定符 const 并不重要。

考虑以下演示程序

#include <stdio.h> 

void f( const int x );

void f( int x )
{
    x += 10;

    printf( "Inside the function x = %d\n", x );
}    


int main( void )  
{ 
    int x = 1;

    printf( "Before calling f x = %d\n", x );

    f( x );

    printf( "After calling f  x = %d\n", x );
}   

它的输出是

Before calling f x = 1
Inside the function x = 11
After calling f  x = 1  

所以对于函数的使用者来说函数的参数x是否有限定符const并不重要。从编译器(和函数的用户)的角度来看,这两个声明都声明了同一个函数。

函数参数是它们的局部变量。并且用户不关心某些局部变量是否会在带有限定符 const 的函数中声明。

注意本声明中的内容

int fputs(const char *s, FILE *stream);

它不是第一个声明为常量的参数。指针指向的数据是常量。

但是在这个声明中

int fputc( const int c, FILE *stream);

参数本身是常量。