C 6장. 함수 #include <stdio.h> int main(void) { int num; printf(“Please enter an integer: "); scanf("%d", &num); if ( num < 0 ) printf("Is negative.\n"); printf("num = %d\n", num); return 0; }
학습목표 ■ 기본적인 함수의 개념에 대해 알아본다. ■ 함수를 정의할 때 필요한 함수의 리턴형, 함수의 이름, 함수의 매개변수에 대해 알아본다. ■ 함수 호출시 주의 사항과 함수의 선언(또는 원형)에 대해 알아본다. ■ 지역 변수와 전역 변수에 대해 알아본다. ■ 함수의 인자 전달 방법에 대해 알아본다. 6장. 함수
목차 6장. 함수 함수의 기본 지역 변수와 전역 변수 함수의 인자 전달 방법 함수의 정의 함수의 호출 함수의 선언 지역 변수 변수의 영역 규칙 함수의 인자 전달 방법 값에 의한 전달 포인터에 의한 전달 6장. 함수
함수 : 프로그램에서 자주 사용되는 코드 블록을 따로 한번만 만들어 두고 필요할 때마다 불러서 사용하는 기능 함수의 기본 함수 : 프로그램에서 자주 사용되는 코드 블록을 따로 한번만 만들어 두고 필요할 때마다 불러서 사용하는 기능 함수를 사용할 때의 장점 코드가 중복되지 않고 간결해진다. 한 번 작성해둔 코드를 여러 번 사용하므로 코드의 재사용성이 증가된다. 기능별로 함수를 작성해서 사용하므로 프로그램의 모듈화가 증대된다. 프로그램의 기능을 함수 단위로 나누어 묶어 두었기 때문에 코드를 수정하기 쉬워진다. 6장. 함수
함수의 기본 함수를 사용하지 않는 경우 함수를 사용하는 경우 6장. 함수
함수의 기본 C 프로그램의 함수들
함수의 기본 함수의 정의 함수와 블랙박스 6장. 함수
함수의 기본 함수의 정의 함수를 정의하는 기본적인 형식 6장. 함수
함수의 리턴형 함수의 기본 함수가 처리 결과로 리턴하는 값의 데이터 형 함수의 정의 함수의 리턴형 함수가 처리 결과로 리턴하는 값의 데이터 형 함수의 리턴형이 void형이면 함수의 리턴 값이 없다는 의미 함수의 리턴형을 생략하면 int형으로 간주된다. 함수는 반드시 하나의 값만 리턴할 수 있다. 6장. 함수
함수의 이름 함수의 기본 함수의 이름도 식별자를 만드는 규칙에 따라서 만들어야 한다. 함수의 정의 함수의 이름 함수의 이름도 식별자를 만드는 규칙에 따라서 만들어야 한다. 어떤 일을 하는 함수인지 명확하게 알 수 있는 이름을 선택한다. 이름이 같은 함수를 여러 번 정의할 수 없다. 6장. 함수
함수의 매개변수 함수의 기본 함수의 기능을 수행하기 위해서 필요한 값을 넘겨주기 위한 변수 인자라고도 부른다. 함수의 정의 함수의 매개변수 함수의 기능을 수행하기 위해서 필요한 값을 넘겨주기 위한 변수 인자라고도 부른다. 함수의 매개변수는 개수에 제한이 없다. 함수가 매개변수를 갖지 않을 때는 ( ) 안에 void라고 적어준다. 6장. 함수
함수의 헤더와 바디 함수의 기본 함수의 정의는 헤더와 바디로 구성된다. 함수의 헤더는 함수의 리턴형, 함수의 이름, 매개변수를 적는 부분이다. 함수의 바디는 { } 안에 함수가 처리할 문장을 나열한 부분이다. 6장. 함수
매개변수와 리턴 값이 모두 없는 함수 함수의 기본 함수의 정의 매개변수와 리턴 값이 모두 없는 함수 리턴 값이 없는 함수는 따로 return문을 쓰지 않아도 함수의 끝을 만나면 자동으로 리턴한다. 함수의 끝을 만나기 전에 리턴하려면 return문을 사용하면 된다. 6장. 함수
함수의 기본 함수의 정의 매개변수는 갖지만 리턴 값이 없는 함수 6장. 함수
함수의 기본 함수의 정의 매개변수와 리턴 값을 모두 갖는 함수 6장. 함수
함수의 기본 함수의 정의 매개변수와 리턴 값을 모두 갖는 함수 6장. 함수
함수를 호출할 때는 함수의 이름을 쓰고 ( ) 안에 함수의 인자를 써준다. 함수의 기본 함수의 호출 함수를 호출할 때는 함수의 이름을 쓰고 ( ) 안에 함수의 인자를 써준다. 인자(argument) : 함수를 호출할 때 직접 넘겨주는 값 함수 호출 시 넘겨준 인자가 함수의 매개변수로 전달된다. 6장. 함수
함수의 기본 함수의 호출 인자 없는 함수의 호출 6장. 함수
인자와 리턴 값을 갖지 않는 함수의 호출 예(1/2) 함수의 기본 함수의 호출 인자와 리턴 값을 갖지 않는 함수의 호출 예(1/2) 01: /* Ex06_01.c */ 02: #include <stdio.h> 03: 04: void PrintHello(void) 05: { 06: printf("Hello World\n"); 07: } 08: 09: void PrintBye(void) 10: { 11: printf("프로그램을 종료합니다.\n"); 12: } 13: PrintHello 함수의 정의 PrintBye 함수의 정의 6장. 함수
인자와 리턴 값을 갖지 않는 함수의 호출 예(2/2) 함수의 기본 함수의 호출 인자와 리턴 값을 갖지 않는 함수의 호출 예(2/2) 14: int main(void) 15: { 16: PrintHello( ); 17: PrintBye( ); 18: 19: return 0; 20: } 함수의 호출 6장. 함수
인자를 갖는 함수의 호출 함수의 기본 인자를 갖는 함수를 호출할 때는 ( )안에 함수의 인자를 콤마(,)로 나열한다. 6장. 함수
리턴 값은 없고, 두 개의 인자를 갖는 함수의 호출 예 함수의 기본 함수의 호출 리턴 값은 없고, 두 개의 인자를 갖는 함수의 호출 예 01: /* Ex06_02.c */ 02: #include <stdio.h> 03: 04: void PrintSumAndAverage(int a, int b) 05: { 06: printf("합계 : %d\n", a + b); 07: printf("평균 : %f\n", (double) (a + b) / 2); 08: } 09: 10: int main(void) 11: { 12: int x, y; 13: 14: PrintSumAndAverage(10, 20); 15: 16: printf("정수를 입력하세요 : "); 17: scanf("%d %d", &x, &y); 18: PrintSumAndAverage(x, y); 19: 20: return 0; 21: } 함수의 정의 인자를 갖는 함수의 호출 인자를 갖는 함수의 호출 6장. 함수
인자와 리턴 값을 갖는 함수의 호출 함수의 기본 함수의 리턴 값을 받아서 다른 수식에 이용할 수 있다. 함수의 호출 6장. 함수
인자와 리턴 값을 갖는 함수의 호출 예(1/2) 함수의 기본 함수의 호출 6장. 함수 01: /* Ex06_03.c */ 02: #include <stdio.h> 03: 04: int GetFactorial(int num) 05: { 06: int i; 07: int fact = 1; 08: for(i = 1 ; i <= num ; i++) 09: fact *= i; 10: return fact; 11: } 12: 13: int GetSum(int num) 14: { 15: int i; 16: int sum = 0; 17: for(i = 1 ; i <= num ; i++) 18: sum += i; 19: return sum; 20: } 21: GetFactorial 함수의 정의 GetSum 함수의 정의 6장. 함수
인자와 리턴 값을 갖는 함수의 호출 예(2/2) 함수의 기본 함수의 호출 6장. 함수 22: int main(void) 23: { 24: int result1, result2; 25: 26: result1 = GetFactorial(10); 27: printf("10 팩토리얼 = %d\n", result1); 28: 29: result2 = GetSum(10); 30: printf("1~10의 합계 = %d\n", result2); 31: 32: return 0; 33: } 인자와 리턴 값을 갖는 함수의 호출 인자와 리턴 값을 갖는 함수의 호출 6장. 함수
함수의 리턴 값이 리턴되는 과정 함수의 기본 함수 안에서 return문이 넘겨주는 값이 함수 호출문의 값이 된다. 함수의 호출 6장. 함수
함수의 기본 함수의 호출 함수 호출 시 주의사항(1/3) 함수의 인자로 수식을 사용하면 먼저 수식의 값을 평가하고 나서 그 값을 다시 함수의 인자로 사용한다. 6장. 함수
함수의 기본 함수의 호출 함수 호출 시 주의사항(2/3) 함수를 호출할 때 넘겨주는 인자의 개수는 함수 정의에 있는 매개변수의 개수와 일치해야 한다. 6장. 함수
함수의 기본 함수의 호출 함수 호출 시 주의사항(3/3) 함수를 호출할 때 인자는 반드시 넘겨주어야 하지만 함수의 리턴 값은 받아올 수도 있고, 받아오지 않을 수도 있다. 잘못된 이름으로 함수를 호출해서는 안 된다.(대소문자까지 정확히 일치하는 이름으로 호출) 6장. 함수
함수를 호출할 때는 반드시 함수 호출보다 앞 쪽에 함수를 정의해주어야 한다. 함수의 기본 함수의 선언 함수를 호출할 때는 반드시 함수 호출보다 앞 쪽에 함수를 정의해주어야 한다. 6장. 함수
함수의 정의보다 앞쪽에서 함수를 호출하는 예(1/2) 함수의 기본 함수의 선언 함수의 정의보다 앞쪽에서 함수를 호출하는 예(1/2) 01: /* Ex06_05.c */ 02: #include <stdio.h> 03: 04: int main(void) 05: { 06: int i_res; 07: double f_res; 08: 09: i_res = GetFactorial(5); 10: printf("5! = %d\n", i_res); 11: 12: f_res = GetMax(0.5, 10.5, 12.5); 13: printf("최대값 = %f\n", f_res); 14: 15: return 0; 16: } 17: 아직 정의되지 않은 함수의 호출 (컴파일 경고) 아직 정의되지 않은 함수의 호출 (컴파일 경고) 6장. 함수
함수의 정의보다 앞쪽에서 함수를 호출하는 예(2/2) 함수의 기본 함수의 선언 함수의 정의보다 앞쪽에서 함수를 호출하는 예(2/2) 18: int GetFactorial(int num) 19: { 20: int i; 21: int fact = 1; 22: for(i = 1 ; i <= num ; i++) 23: fact *= i; 24: return fact; 25: } 26: 27: double GetMax(double a, double b, double c) 28: { 29: double max; 30: max = a > b ? a : b; 31: max = c > max ? c : max; 32: return max; 33: } GetFactorial 함수의 정의 잘못된 실행 결과 GetMax 함수의 정의 6장. 함수
함수의 선언(1/2) 함수의 기본 함수가 정의된 위치에 관계 없이 함수를 호출할 수 있게 한다. 함수의 리턴형, 이름, 매개변수에 대한 정보만을 미리 알려주는 것 함수의 원형(prototype)이라고도 한다. 6장. 함수
함수의 선언(2/2) 함수의 기본 함수 선언 시 매개변수의 이름은 생략할 수 있다. 함수 선언문의 끝에 세미콜론(;)을 써주어야 한다. 6장. 함수
함수의 선언을 사용하는 경우의 예(1/2) 함수의 기본 함수의 선언 6장. 함수 01: /* Ex06_06.c */ 02: #include <stdio.h> 03: 04: int GetFactorial(int num); 05: double GetMax(double a, double b, double c); 06: 07: int main(void) 08: { 09: int i_res; 10: double f_res; 11: 12: i_res = GetFactorial(5); 13: printf("5! = %d\n", i_res); 14: 15: f_res = GetMax(0.5, 10.5, 12.5); 16: printf("최대값 = %f\n", f_res); 17: 18: return 0; 19: } 20: 함수의 선언 함수의 선언 함수의 호출 함수의 호출 6장. 함수
함수의 선언을 사용하는 경우의 예(2/2) 함수의 기본 함수의 선언 6장. 함수 21: int GetFactorial(int num) 22: { 23: int i; 24: int fact = 1; 25: for(i = 1 ; i <= num ; i++) 26: fact *= i; 27: return fact; 28: } 29: 30: double GetMax(double a, double b, double c) 31: { 32: double max; 33: max = a > b ? a : b; 34: max = c > max ? c : max; 35: return max; 36: } GetFactorial 함수의 정의 GetMax 함수의 정의 6장. 함수
함수의 정의(definition) 함수의 호출(call) 함수의 선언(declaration) 함수의 선언만 생략 가능 함수의 기본 함수의 선언 함수의 정의(definition) 함수의 리턴형, 함수의 이름, 함수의 매개변수를 써준 다음 { } 안에 실제로 함수가 처리할 내용을 기술 함수의 호출(call) 앞에서 선언되거나 정의된 함수를 이용 인자를 넘겨주고 리턴 값을 받아올 수 있다. 함수의 선언(declaration) 함수의 내용을 알려주지는 않지만 함수 호출에 필요한 리턴형, 함수의 이름, 매개변수 정보를 미리 알려준다. 함수의 선언만 생략 가능 6장. 함수
지역 변수 전역 변수 지역 변수와 전역 변수 함수 안에 선언된 변수 지역 변수가 선언된 함수 안에서만 사용될 수 있다. 함수 밖에 선언된 변수 여러 함수에서 사용될 수 있는 변수 6장. 함수
지역 변수(1/4) 지역 변수와 전역 변수 함수 안에서 만들어지고, 함수 안에서만 사용되는 변수 지역 변수는 함수가 리턴할 때 항상 자동으로 없어진다. 변수는 함수의 시작 부분이나 블록의 시작 부분에서 선언할 수 있다. 6장. 함수
지역 변수와 전역 변수 지역 변수 지역 변수(2/4) 지역 변수는 선언된 블록 안에서만 사용 가능하다. 6장. 함수
다른 함수에 선언된 변수의 사용 지역 변수와 전역 변수 지역 변수 6장. 함수 01: /* Ex06_07.c */ 02: #include <stdio.h> 03: 04: void PrintCount(void); 05: 06: int main(void) 07: { 08: int count = 0; 09: 10: printf("main: count = %d\n", count); 11: 12: return 0; 13: } 14: 15: void PrintCount(void) 16: { 17: printf("PrintCount: count = %d\n", count); 18: } main 함수 안에서는 count 사용 가능 PrintCount 함수 안에서 count 사용시 컴파일 에러 6장. 함수
지역 변수와 전역 변수 지역 변수 지역 변수(3/4) 서로 다른 함수에서 같은 이름의 변수를 선언하면, 이름은 같지만 서로 다른 변수가 된다. 6장. 함수
서로 다른 함수에서 같은 이름의 변수를 선언하는 경우 지역 변수와 전역 변수 지역 변수 서로 다른 함수에서 같은 이름의 변수를 선언하는 경우 01: /* Ex06_08.c */ 02: #include <stdio.h> 03: 04: void PrintCount(void); 05: 06: int main(void) 07: { 08: int count = 0; 09: printf("main: count = %d\n", count); 10: 11: PrintCount( ); 12: 13: return 0; 14: } 15: 16: void PrintCount(void) 17: { 18: int count = 100; 19: printf("PrintCount: count = %d\n", count); 20: } main 함수 안에 지역 변수 count 선언 main 함수 안에 선언된 count 사용 PrintCount 함수 안에 지역 변수 count 선언 PrintCount 함수 안에 선언된 count 사용 6장. 함수
같은 함수를 여러 번 호출하는 경우 지역 변수와 전역 변수 지역 변수 6장. 함수 01: /* Ex06_09.c */ 02: #include <stdio.h> 03: 04: void TestLocal(void); 05: 06: int main(void) 07: { 08: TestLocal( ); 09: TestLocal( ); 10: 11: return 0; 12: } 13: 14: void TestLocal(void) 15: { 16: int num = 0; 17: 18: printf("num = %d\n", num++); 19: } 같은 함수를 여러 번 호출 지역 변수 num은 함수가 호출될 때마다 새로 생성 6장. 함수
지역 변수(4/4) 지역 변수와 전역 변수 함수의 매개변수도 지역 변수이다. 지역 변수는 따로 초기화하지 않으면 쓰레기 값을 갖는다. 6장. 함수
전역 변수(1/2) 지역 변수와 전역 변수 프로그램 전체에서 사용될 수 있는 변수 프로그램이 시작될 때 한 번만 생성되고, 프로그램이 수행되는 동안 여러 함수에서 사용되다가, 프로그램이 종료될 때 비로소 해제된다. 6장. 함수
전역 변수의 선언 및 사용(1/2) 지역 변수와 전역 변수 전역 변수 6장. 함수 01: /* Ex06_11.c */ 02: #include <stdio.h> 03: 04: void PrintCount(void); 05: void Increment(void); 06: void Decrement(void); 07: 08: int count; 09: 10: int main(void) 11: { 12: count = 0; 13: 14: PrintCount( ); 15: Increment( ); 16: Increment( ); 17: PrintCount( ); 18: 전역 변수 count의 선언 전역 변수 count 의 사용 6장. 함수
함수 사이에 선언된 전역 변수(2/2) 지역 변수와 전역 변수 전역 변수 6장. 함수 19: Decrement( ); 20: PrintCount( ); 21: 22: return 0; 23: } 24: 25: void PrintCount(void) 26: { 27: printf("count = %d\n", count); 28: } 29: 30: void Increment(void) 31: { 32: count++; 33: } 34: 35: void Decrement(void) 36: { 37: count--; 38: } 전역 변수 count 의 사용 전역 변수 count 의 사용 전역 변수 count 의 사용 6장. 함수
전역 변수(2/2) 지역 변수와 전역 변수 전역 변수의 선언문 다음에 정의된 함수에서만 전역 변수를 사용할 수 있다. 전역 변수의 선언문은 소스 파일의 시작 부분에 넣어주는 것이 좋다. 전역 변수는 따로 초기화하지 않으면 자동으로 0으로 초기화된다. 6장. 함수
함수 사이에 선언된 전역 변수(1/2) 지역 변수와 전역 변수 10번째 줄에서 컴파일 에러가 발생하므로 실행할 수 없다! 01: /* Ex06_12.c */ 02: #include <stdio.h> 03: 04: void PrintCount(void); 05: void Increment(void); 06: void Decrement(void); 07: 08: int main(void) 09: { 10: count = 0; 11: 12: Increment( ); 13: PrintCount( ); 14: 15: return 0; 16: } 17: 18: int count; 19: 10번째 줄에서 컴파일 에러가 발생하므로 실행할 수 없다! 선언 전에 전역 변수 count를 사용했으므로 컴파일 에러 전역 변수 count의 선언 6장. 함수
함수 사이에 선언된 전역 변수(2/2) 지역 변수와 전역 변수 전역 변수 6장. 함수 20: void PrintCount(void) 21: { 22: printf("count = %d\n", count); 23: } 24: 25: void Increment(void) 26: { 27: count++; 28: } 29: 30: void Decrement(void) 31: { 32: count--; 33: } 전역 변수 count 의 사용 전역 변수 count 의 사용 전역 변수 count 의 사용 6장. 함수
변수의 영역 규칙(1/2) 지역 변수와 전역 변수 블록 범위가 달라질 때는 같은 이름의 변수를 여러 번 선언할 수 있다. 항상 가까운 블록 안에 선언된 변수 이름이 우선적으로 사용된다. 6장. 함수
지역 변수와 전역 변수 변수의 영역 규칙 변수의 영역 규칙(2/2) 전역 변수와 지역 변수의 이름이 같아지는 것을 막기 위해서 전역 변수 이름에는 g_를 접두사로 붙인다. 6장. 함수
변수의 영역 규칙(1/2) 지역 변수와 전역 변수 변수의 영역 규칙 6장. 함수 01: /* Ex06_13.c */ 02: #include <stdio.h> 03: 04: void Test(void); 05: int num = 10; 06: 07: int main(void) 08: { 09: int num = 20; 10: 11: while( 1 ) 12: { 13: int num = 30; 14: 15: printf("num = %d\n", num++); 16: 17: if(num > 25) 18: break; 19: } 전역 변수 num의 선언 지역 변수 num의 선언 지역 변수 num의 선언 while 안에 선언된 지역 변수 num 사용 6장. 함수
변수의 영역 규칙(2/2) 지역 변수와 전역 변수 변수의 영역 규칙 6장. 함수 20: printf("num = %d\n", num); 21: 22: Test( ); 23: 24: return 0; 25: } 26: 27: void Test(void) 28: { 29: printf("num = %d\n", num); 30: } main 안에 선언된 지역 변수 num 사용 전역 변수 num 사용 6장. 함수
함수의 인자 전달 방법 값에 의한 전달 방법 포인터에 의한 전달 방법 6장. 함수
함수의 인자 전달 방법 값에 의한 전달 값에 의한 전달 방법 함수를 호출할 때 넘겨주는 인자의 값을 함수 정의에 있는 매개변수로 복사해서 전달하는 방식 복사에 의한 전달 함수 안에서 매개변수의 값을 변경해도 함수를 호출한 곳에 있는 인자의 값은 바뀌지 않는다. 6장. 함수
Swap 함수의 예(1/2) 함수의 인자 전달 방법 값에 의한 전달 6장. 함수 01: /* Ex06_14.c */ 02: #include <stdio.h> 03: 04: void Swap(int x, int y); 05: 06: int main(void) 07: { 08: int a = 10; 09: int b = 20; 10: 11: printf("Swap 전의 a = %d, b = %d\n", a, b); 12: 13: Swap(a, b); 14: 15: printf("Swap 후의 a = %d, b = %d\n", a, b); 16: 17: return 0; 18: } 19: Swap 함수의 선언 Swap 함수의 호출 6장. 함수
Swap 함수의 예(2/2) 함수의 인자 전달 방법 두 변수의 값이 맞교환되지 않았다. 값에 의한 전달 6장. 함수 20: void Swap(int x, int y) 21: { 22: int temp; 23: 24: temp = x; 25: x = y; 26: y = temp; 27: } Swap 함수의 정의 두 변수의 값이 맞교환되지 않았다. 6장. 함수
함수의 인자 전달 방법 값에 의한 전달 Swap 함수의 수행 과정(1/2) 6장. 함수
함수의 인자 전달 방법 값에 의한 전달 Swap 함수의 수행 과정(1/2) 6장. 함수
매개변수로 함수의 처리 결과를 받아오는 경우 함수의 인자 전달 방법 작은 값과 큰 값이 구해지지 않았다! 값에 의한 전달 01: /* Ex06_15.c */ 02: #include <stdio.h> 03: 04: void GetSmallerAndLarger(int a, int b, int smaller, int larger); 05: 06: int main(void) 07: { 08: int smaller = 0, larger = 0; 09: 10: GetSmallerAndLarger(10, 20, smaller, larger); 11: 12: printf("smaller = %d, larger = %d\n", smaller, larger); 13: 14: return 0; 15: } 16: 17: void GetSmallerAndLarger(int a, int b, int smaller, int larger) 18: { 19: smaller = a < b ? a : b; 20: larger = a > b ? a : b; 21: } 결과를 받아올 변수의 선언 작은 값과 큰 값이 구해지지 않았다! 함수 호출 매개변수에 결과 저장 6장. 함수
포인터에 의한 전달 방법 함수의 인자 전달 방법 변수의 값을 전달하는 대신 변수의 주소를 전달하는 방식 포인터에 의한 전달 6장. 함수
학습정리 함수의 기본 함수의 정의 : 함수의 리턴형, 함수의 이름, 함수의 매개변수를 써준 다음 { } 안에 실제로 함수가 처리할 내용을 기술한다. 함수의 호출 : 함수의 이름 다음에 ( )안에 인자를 써준다. 함수의 선언 : 함수 호출에 필요한 리턴형, 함수의 이름, 매개변수 정보를 미리 알려주는 문장이다. 6장. 함수
지역 변수와 전역 변수 함수의 인자 전달 방법 학습정리 지역 변수 : 함수 안에서 선언되고, 함수 안에서만 사용된다. 따로 초기화하지 않으면 쓰레기 값을 갖는다. 전역 변수 : 함수 밖에서 선언되고, 프로그램 전체에서 사용된다. 따로 초기화하지 않아도 0으로 초기화된다. 영역 규칙 : 가장 가까운 블록에 선언된 변수가 항상 우선적으로 사용된다. 함수의 인자 전달 방법 값에 의한 전달 : 인자의 값을 매개변수에 복사해서 전달한다. 함수 안에서 매개변수의 값을 변경해도 함수를 호출한 곳에 있는 인자의 값은 바뀌지 않는다. 포인터에 의한 전달 : 함수의 인자로 변수의 주소를 전달한다. 6장. 함수
6장. 함수 수고하셨습니다. 질문 있습니까? NEXT Chapter 7장. 배열과 문자열