C编程-goto使用

Posted by 周思进 on August 23, 2019

工作中经常会看到这样的接口代码,先获取一个资源(比如文件描述符、动态申请的内存等),进行相应处理,如果处理正常,会申请另外资源再进行相应处理,前面获取的资源也会在下面继续使用,如果中间处理存在异常,就需要进行各种资源释放操作,类似下面这样的代码处理流程

int main(int argc, char *argv[])
{
	int fd = -1;
	char *buf = NULL;
	off_t file_len = 0;
	int ret = -1;

	fd = open("./test.txt", O_RDWR);
	if (-1 == fd)
	{
		return -1;
	}

	file_len = lseek(fd, 0, SEEK_END);
	if (-1 == file_len)
	{
		close(fd);
		return -1;
	}
	
	buf = malloc(file_len);
	if (NULL == buf)
	{
		close(fd);
		return -1;
	}

	// 需要将文件偏移指针重新指向文件头
	ret = lseek(fd, 0, SEEK_SET);
	if (ret != 0)
	{
		close(fd);
		free(buf);
		return -1;
	}

	ret = read(fd, buf, file_len);
	if (-1 == ret)
	{
		close(fd);
		free(buf);
		return -1;
	}

	printf("buf:%s\n", buf);

	close(fd);
	free(buf);
	return 0;
}

可以看到,就这样的一个小功能,中间就涉及很多处资源的释放操作。而实际开发中接触的接口往往涉及更多需要释放的资源,中间一处出错,就需要多条语句进行释放操作,而且是很多出错的地方都要这样执行。

这种场景如果使用goto语句就会好很多,比如修改后:

int main(int argc, char *argv[])
{
	int fd = -1;
	char *buf = NULL;
	off_t file_len = 0;
	int ret = -1;

	fd = open("./test.txt", O_RDWR);
	if (-1 == fd)
	{
		return -1;
	}

	file_len = lseek(fd, 0, SEEK_END);
	if (-1 == file_len)
	{
		goto CLOSE_FD;
		ret = -1;
	}
	
	buf = malloc(file_len);
	if (NULL == buf)
	{
		goto CLOSE_FD;
		ret = -1;
	}

	// 需要将文件偏移指针重新指向文件头
	ret = lseek(fd, 0, SEEK_SET);
	if (ret != 0)
	{
		goto FREE_BUF;
		ret = -1;
	}

	ret = read(fd, buf, file_len);
	if (-1 == ret)
	{
		goto FREE_BUF;
		ret = -1;
	}

	ret = 0;
	printf("buf:%s\n", buf);

FREE_BUF:
	free(buf);
CLOSE_FD:
	close(fd);
	return ret;
}

上面的修改可以看出几点:

1、所有的资源释放操作都放在函数最后,越往后申请的资源则是放在前面进行释放,这样就不怕中间错误处理跳转前面申请的资源没有释放。

2、涉及新资源的释放,会有一个新的goto标号,且最好跟所要涉及的释放资源相吻合。

3、goto标号最好顶头写,不要存在缩进,这样易于识别查看


goto语句除了上面进行错误处理释放资源这样的操作,其他情况估计大家也都看多了书上说的,还是要慎用。