2.1 함수 선언 이해하기
2.1.1 함수 선언을 이해하는 방법
먼저 문장을 보면 다음과 같습니다.
(*(void(*)())0)();
이러한 표현식을 구성하는 데는 단 하나의 간단한 규칙이 있습니다. 사용되는 방식으로 선언하십시오.
모든 C 변수의 선언은 두 부분으로 구성됩니다. 유형 및 식과 유사한 선언자 집합입니다. 선언자는 표면적으로 표현식과 유사하며 해당 평가는 선언에 제공된 유형의 결과를 반환해야 합니다.
-
간단한 변수 선언:
float f; //含义:当对f进行求值时,表达式f的类型为浮点数类型。因为声明符与表达式类似,所以也可以在声明符中任意使用括号: float ((f)); //含义:((f))的类型是浮点类型,由此可以推知,f也是浮点类型。
-
함수 및 포인터 유형 선언
float ff(); //含义:表达式ff()的求值结果是一个浮点数,也就是说,ff是一个返回值为浮点类型的函数。 float *pf; //含义:*pf是一个浮点数,也就是说,pf是一个指向浮点数的指针。
결론: 선언에서 변수 이름을 제거하고 선언 끝에 세미콜론을 제거한 다음 나머지를 괄호로 "캡슐화"하여 캐스터를 가져옵니다.
참고: 아래에 함수 포인터가 있습니다.
void (*fp)();
fp는 함수 포인터이므로 *fp는 포인터가 가리키는 함수이므로 (*fp)() 함수를 호출하는 방법입니다. ANSI C 표준에서는 프로그래머가 위의 표현을 fp()로 축약할 수 있습니다. 그러나 이 표기법은 약칭일 뿐입니다.
식 (*fp)()에서 함수 연산자()가 단항 연산자 *보다 우선 순위가 높기 때문에 *fp 주위의 괄호는 매우 중요합니다. *fp 주위에 괄호가 없으면 *fp()는 실제로 ANSI C가 *((*fp)())의 약어로 사용하는 *(fp())와 정확히 같은 의미를 갖습니다. (*fp와 fp는 등가, 즉 위의 정리가 적용됨)
2.1.2 예제로 문장 이해하기
2.1.2.1 예 1
(*(void(*)())0)();
//将0进行强制类型转换为(void (*)()),即函数指针类型,然后对其进行解引用,解引用之后就找到了那个函数,然后再进行函数调用
//此处就是把0当作是一个地址,本质上就是一个函数的调用
2.1.2.2 예 2
void (*signal(int,void(*)(int)))(int);
//首先signal先和圆括号先结合,形成一个函数,这个函数有两个参数,参数1是一个整数,参数2是一个函数指针,该函数指针指向的函数的参数为int类型,返回类型为void类型,signal函数的返回类型为void(*)(int),即一个函数指针类型,该函数指针指向的函数参数类型为int,返回类型为void。
2.2 연산자 우선순위
연산자 우선 순위 요약
2.2.1 일반적인 실수
2.2.1.1 오류 예 1
if(flags & FLAG!=0 )
if 조건문의 판단조건으로 flag와 FLAG&의 결과를 사용하고자 하지만 우선순위의 문제로 인해 위의 표현을 다음과 같이 조합하여 표현의 의미가 우리와 상반된다.
if(flags & (FLAG!=0))
2.2.1.2 오류 2
r = h<<4 + low;//r的值等于h左移4位后的值与变量low的和
그러나 실제로 다음과 같이 결합됩니다.
r = hi<< (4 + low);
표현된 의미가 우리가 표현하고자 하는 것과 반대입니다.
2.2.1.3 오류 예 3
while(c = getc(in)!=EOF)
putc(c,out);
위의 문장에서 우리는 한 파일을 다른 파일로 복사하려고 하지만 실제로는 다음과 같이 결합됩니다.
while(c = (getc(in)!=EOF))
표현의 의미가 우리가 달성하고자 하는 목적을 달성하지 못합니다. 여기서 getc(in) 함수의 반환 값은 EOF와 비교한 후 폐기되는 임시 변수일 뿐입니다. 따라서 파일의 결과 복사본에는 이진 1바이트 스트림 집합만 포함됩니다.
2.2.1.4 오류 4
if((t=BTYPE(pt1->aty)==STRTY) || t==UNIONTY)
이 코드 줄의 원래 의도는 먼저 t에 값을 할당한 다음 t가 STRTY 또는 UNIONTY와 같은지 여부를 결정하는 것입니다.
그러나 실제 조합은 다음과 같습니다.
if((((t=BTYPE(pt1->aty))==STRTY) || t)==UNIONTY)
실제 결과는 상당히 다릅니다. BTYPE(pt1->aty)의 값이 STRTY인지 여부에 따라 t의 값은 1 또는 0입니다. t의 값이 0이면 UNIONTY와 더 비교할 수 있습니다. .
2.2.1.5 오류 5
while(c == '\t' || c = ' '|| c == '\n')
c = getc(f);
이 예는 불법입니다. 할당 연산자는 while 절에서 다른 연산자보다 우선 순위가 낮기 때문에 위의 예를 설명할 수 있습니다.
while((c == '\t' || c) = (' '|| c == '\n'))
물론 이것은 (c == '\t' || c)
할당 연산자의 좌변에 나타날 수 없기 때문에 불법입니다.
2.2.2 연산자의 연관 이해
*p++;
//上面的代码应该像下面这样进行理解:
*(p++);//++和*都是单目运算符,具有相同的优先级,但是结合性是自右向左的
2.2.3 관계 연산자의 우선 순위
6개의 관계연산자의 우선순위가 같지 않고 >, >=, <, <=의 우선순위가 두 연산자 ==, !=보다 우선순위가 높기 때문에 다음과 같이 쓰는 경우가 많다.
if(a < b == c < d)
//上面代码等价于
if((a < b) == (c < d))
2.2.4 오른쪽에서 왼쪽으로 우선 순위 요약
단항 연산자, 삼항 연산자, 할당 연산자
2.3 명령문의 끝으로 세미콜론을 기록하십시오.
2.3.1 세미콜론 추가
참고: if 또는 while 절 뒤에 세미콜론을 추가하지 마십시오. 세미콜론을 뒤에 넣으면 계산할 수 없는 결과가 발생하여 코드 오류가 발생하고 종종 찾기가 어렵습니다.
예:
if(x[i] > big);
big = x[i];
위의 코드는 실제로 다음과 같습니다.
if(x[i] > big) {}
big = x[i];
즉, 조건이 참인지 아닌지에 관계없이 big = x[i] 문을 실행합니다.
2.3.2 세미콜론 누락
참고: 세미콜론을 누락하면 종종 측정할 수 없는 결과를 초래할 수 있습니다.
예:
if(n<3)
return
logrec.date = x[0];
위의 코드는 다음 코드와 동일합니다.
if(n<3)
return logrec.date = x[0];
이때, n<3 조건을 만족하면 큰 문제가 없을 수도 있지만, n<3 조건을 만족하지 않으면 logrec.date = x[0] 문을 건너뛴다. 이것은 우리가 표현하고자 하는 것과 반대입니다.
다음 코드가 있습니다.
struct logrec
{
int date;
int time;
int code;
}//分号被省略
main()
{
···
}
세미콜론이 생략되지 않은 경우 main() 함수의 반환 값 형식은 int 형식(컴파일러 기본값)이고 생략 후 반환 형식은 구조체 형식입니다.
2.4 switch 문
참고: C 언어의 case 문 다음에 다음 case 문을 계속 실행하지 않으려면 case 문 끝에 break를 추가하여 현재 case 문을 종료해야 합니다.
2.5 기능 목록
==C 언어 요구 사항: 함수를 호출할 때 함수가 매개변수를 사용하지 않더라도 매개변수 목록이 포함되어야 합니다. == 따라서 f가 함수이면
f();
함수 호출 문이고,
f;
그러나 그것은 아무 것도 하지 않는 진술이다. 이 문은 함수를 호출하지 않고 함수 f의 주소를 계산합니다.