【问题标题】:Why does fputs() require a constant as first parameter and not fputc()?为什么 fputs() 需要一个常量作为第一个参数而不是 fputc()?
【发布时间】:2019-12-07 23:15:02
【问题描述】:
int fputc(int c, FILE *stream);

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

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

【问题讨论】:

  • 因为fputc 无法将c 更改为外部,即使它真的想要。

标签: c function parameters declaration definition


【解决方案1】:

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

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

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

注意1:函数fputs中的const修饰符是char类型(const char *s),这意味着指向的内存不能被改变。如果const 在输入参数s (char * const s) 上,它不会保护指向的内存,它只会保护指针本身,它无论如何都是按值传递的。

注意 2: 正如Eric Postpischil 在评论中提到的,在Vlad from Moscowanswer 中显示,如果 const 修饰符在函数声明中而不是在函数定义中,没有效果。

【讨论】:

  • 一个const修饰符到一个参数(实际参数,不是子组件,例如char * const s,不是const char *s)在一个函数声明中不是定义无效;它不会阻止函数更改参数。 (当然,不能[直接]更改参数,因为它是按值传递的。但是函数可以更改其参数,除非它们使用const 定义。)
【解决方案2】:

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

所以这两个函数声明

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);

参数本身就是常数。

【讨论】:

    【解决方案3】:

    const char *s 并不意味着s 必须指向一个常量。表示fputs不允许修改s所指向的内容。

    【讨论】:

      【解决方案4】:

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

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

      【讨论】:

        【解决方案5】:

        第一个参数const不用做;参数的“顶级”是复制的,而不是引用的,所以const 所做的只是阻止被调用的函数修改它自己的参数副本。

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

        【讨论】:

        • const 放入int fputc(int c, FILE *stream); 不会阻止fputc 修改其c 的副本。不是定义的声明中的const 无效。
        • @EricPostpischil:我假设您的意思是fputc 的定义将决定它是否是const,而不仅仅是原型声明?因为如果您定义一个采用const int c 的函数并尝试在其中修改c,它肯定会抱怨(例如,gcc 死于error: assignment of read-only parameter ‘c’)。
        猜你喜欢
        • 2013-09-18
        • 2012-11-08
        • 1970-01-01
        • 1970-01-01
        • 2016-03-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-06-21
        相关资源
        最近更新 更多