4

【C进阶】8、goto和void分析

 3 years ago
source link: https://segmentfault.com/a/1190000040590368
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Summary

1) 一般工程开发中需要禁用goto语句,不同的编译器对goto语句的错误处理可能不同。

2)在C语言中,如果函数没写返回值,则默认返回值类型是int;如果函数没有写参数列表,则函数接受任意数量的参数
因此,如果函数没有返回值,必须显式声明返回值类型为void;如果函数没有参数,则必须声明参数列表为void。

3)void是一种基础类型,但不是基础数据类型,所以无法用来定义变量(C语言没规定void是多大内存空间的别名)。

4)对于标准C语言规范,不允许sizeof(void)这种写法,如bcc编译器;对于扩展C语言,可能允许sizeof(void)这种写法,如gcc编译器,输出为1。

5)void*指针的主要作用是:用于接收任意类型的指针。在C语言中,void*type*可以相互转换;在C++中,void*可以作为左值接收任意类型的指针,作为右值时,必须进行强制类型转换

goto和void

1、goto

goto语句带有很浓厚的汇编语言特性,能够跳转到指定的语句,如同汇编语言的跳转指令。
在工程实践中,一般都禁用“goto”。goto会破坏程序的结构,带来意想不到的错误

// 代码示例:以下代码输出什么?

int main()
{
goto End;
    int i = 0;
End:
    printf("i = %d\n", i);
    return 0;
}
  • gcc编译器:编译错误error,提示i变量的初始化被跳过了。
  • vs编译器:编译警告warning,提示i未初始化,但是编出了可执行程序。运行的结果是随机值,意料之外的错误!

2、void

2.1 void修饰返回值和参数

在C语言中:

  • 如果函数没有返回值,那么应该将其声明为void
  • 如果函数没有参数,应该声明其参数为void

注意, C语言中:

  • 如果函数没写返回值,默认的返回值类型是int
  • 如果函数没有声明参数列表,默认接受任意多参数

    f()
    {
    }
    
    int main()
    {
      int i = f(1, 2, 3);        // ok
    
      return 0;
    }

2.2 是否存在void类型的变量?

结论:不存在void类型的变量

void是一种基础类型,但不是基础数据类型;C语言中没有定义void究竟是多大内存的别名,所以也无法定义对应的变量。

int main()
{
    void var;        // error
    void arr[5];     // error

    return 0;
}
  • ANSI C:标准C语言规范,如bcc编译器
  • 扩展C:在ANSI C的基础上进行了扩展,如gcc编译器

    // void类型有大小么?
    
    int main()
    {
      prinft("%d\n", sizeof(void));
      return 0;
    }
  • gcc编译器,Demo可以编过,输出为1
  • bcc编译器,编译错误,提示void是不允许的类型。

2.3 void类型的指针

  • 在C语言中,对指针类型的检查不那么严格,所以void类型的指针可以和任意数据类型的指针进行相互转换

    // test.c
    int main()
    {
      int* p = nullptr;
    
      void* pv = p;         // ok
      
      char* pc = pv;        // ok
      return 0;
    }
  • 在C++语言中,对类型进行了增强,同事也兼容了C语言中的写法。void可以作为左值接受任意类型的指针,但是,void作为右值时,就必须进行强制类型转换

    // test.cpp
    
    int main()
    {
      void* pv = nullptr;        // 初始化是个好习惯
      
      int* pi = pv;          // error, invalid conversion from void* to int*
      int* pi = (int*)pv;    // ok, due to cast
    
      return 0;
    }

总结:void*指针的主要作用是,用于接收任意类型的指针
示例Demo:将数组所占内存全部置0

void MemSet(void* src, int length, unsigned char n)
{
    unsigned char* p = (unsigned char*)src;
    int i = 0;
    for(i=0; i<length; i++)
    {
        p[i] = n;
    }
}

int main()
{
    int a[5];
    int i = 0;

    MemSet(a, sizeof(a), 0);

    for(i=0; i<5; i++)
    {
        printf("%d\n", a[i]);
    }

    return 0;
}

本文总结自“狄泰软件学院”唐佐林老师《C语言进阶课程》。
如有错漏之处,恳请指正。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK