나는 C에서 모든 변수가 함수의 시작 부분에 선언되어야한다고 생각했습니다. C99에서 규칙은 C ++에서와 동일하지만 C89 / ANSI C에 대한 변수 선언 배치 규칙은 무엇입니까?
다음 코드는 gcc -std=c89
및로 성공적으로 컴파일됩니다 gcc -ansi
.
#include <stdio.h>
int main() {
int i;
for (i = 0; i < 10; i++) {
char c = (i % 95) + 32;
printf("%i: %c\n", i, c);
char *s;
s = "some string";
puts(s);
}
return 0;
}
의 선언 안 c
및 s
C89 / ANSI 모드에서 오류가 발생할?
답변
GCC s
가 C89 또는 ANSI 표준의 일부가 아니더라도 GNU 확장으로 선언을 허용하므로 성공적으로 컴파일됩니다 . 해당 표준을 엄격히 준수하려면 -pedantic
플래그 를 전달해야합니다 .
블록 c
시작시 선언은 { }
C89 표준의 일부입니다. 블록은 기능 일 필요는 없습니다.
답변
C89의 경우 스코프 블록 시작시 모든 변수를 선언해야합니다 .
따라서 char c
선언은 for 루프 범위 블록의 맨 위에 있으므로 유효합니다. 그러나 char *s
선언은 오류가되어야합니다.
답변
블록 맨 위에 변수 선언을 그룹화하는 것은 오래된 기본 C 컴파일러의 한계로 인해 레거시 일 가능성이 높습니다. 모든 현대 언어는 최신 시점에서 지역 변수 선언을 권장하고 때로는 시행하기도합니다. 실수로 임의의 값을 사용하는 위험을 제거하기 때문입니다. 선언과 초기화를 분리하면 가능한 경우 “const”(또는 “final”)를 사용하지 못하게됩니다.
C ++은 불행히도 C와의 이전 버전과의 호환성을 위해 이전의 최고 선언 방법을 계속 수용합니다 (하나의 C 호환성은 다른 많은 것들 중에서 하나입니다 …). 그러나 C ++은 그것을 멀리하려고합니다.
- C ++ 참조의 디자인은 이러한 최상위 그룹을 허용하지도 않습니다.
- C ++ 로컬 객체 의 선언과 초기화를 분리 하면 추가 생성자 비용을 지불하지 않아도됩니다. 인수없는 생성자가 없으면 다시 분리 할 수 없습니다!
C99가 C를 같은 방향으로 움직이기 시작합니다.
로컬 변수가 선언 된 위치를 찾지 못할 경우 훨씬 큰 문제가 있음을 의미합니다. 둘러싸는 블록이 너무 길어서 분할되어야합니다.
https://wiki.sei.cmu.edu/confluence/display/c/DCL19-C.+Minimize+the+scope+of+variables+and+functions
답변
구문 적 관점보다는 유지 관리 성 측면에서 최소한 세 가지 사고가 있습니다.
-
함수 시작 부분에 모든 변수를 선언하면 한 위치에 있고 포괄적 인 목록을 한눈에 볼 수 있습니다.
-
모든 변수를 처음 사용한 장소에 최대한 가깝게 선언하면 왜 각 변수 가 필요한지 알 수 있습니다.
-
가장 안쪽 범위 블록의 시작 부분에 모든 변수를 선언하므로 가능한 한 빨리 범위를 벗어나 컴파일러가 메모리를 최적화하고 의도하지 않은 위치에서 실수로 변수를 사용하는지 알려줍니다.
나는 일반적으로 첫 번째 옵션을 선호합니다. 다른 사람들은 종종 선언을위한 코드를 찾아야합니다. 모든 변수를 미리 정의하면 디버거에서 쉽게 초기화하고 볼 수 있습니다.
때로는 더 작은 스코프 블록 내에서 변수를 선언하지만, 타당한 이유가 있습니다. 그 이유는 매우 적습니다. fork()
자식 프로세스에서만 필요한 변수를 선언하기 위해 a 다음에 한 가지 예가 있습니다 . 나에게이 시각적 표시기는 그 목적을 알려주는 유용한 정보입니다.
답변
다른 사람들이 언급했듯이, GC는 ‘pedantic’검사를 사용하지 않는 한 ‘C89’모드에 있더라도 이와 관련하여 (그리고 호출 된 인수에 따라 다른 컴파일러) 가능합니다. 솔직히 말하면, pedantic을 사용하지 않는 좋은 이유는 많지 않습니다. 고품질의 현대 코드는 항상 경고없이 컴파일해야합니다 (또는 컴파일러에게 의심스러운 특정 작업을 실수로 의심하는 경우는 거의 없습니다). 따라서 코드 설정을 사용하여 코드를 컴파일 할 수 없으면주의를 기울여야합니다.
C89는 변수가 각 범위 내에서 다른 문장보다 먼저 선언되어야하며, 이후 표준에서는 사용하기에 더 가까운 선언 (보다 직관적이고 효율적일 수 있음), 특히 ‘for’루프에서 루프 제어 변수의 동시 선언 및 초기화를 허용합니다.
답변
언급 된 바와 같이, 여기에는 두 가지 사고 학교가 있습니다.
1) 연도가 1987 년이므로 모든 기능을 최상으로 선언하십시오.
2) 최초 사용에 가장 가깝고 가능한 가장 작은 범위에서 선언하십시오.
이것에 대한 나의 대답은 DO BOTH입니다! 설명하겠습니다 :
긴 기능의 경우 1) 리팩토링을 매우 어렵게 만듭니다. 개발자가 서브 루틴 개념에 반대하는 코드베이스에서 작업하는 경우 함수 시작시 50 개의 변수 선언이 있으며 그 중 일부는 for 루프의 “i”일 수 있습니다. 기능의 하단.
따라서 나는 이것으로부터 최고 -PTSD 선언을 개발했고 옵션 2)를 종교적으로하려고했다.
짧은 기능 하나 때문에 옵션 1로 돌아 왔습니다. 함수가 충분히 짧으면 지역 변수가 거의 없으며 함수가 짧기 때문에 함수의 맨 위에 놓으면 첫 번째 사용에 가깝습니다.
또한 맨 위에 선언하고 싶지만 초기화에 필요한 계산을 수행하지 않은 경우 “선언 및 NULL로 설정”의 반 패턴은 초기화해야하는 항목이 인수로 수신되기 때문에 해결되지 않습니다.
이제 내 생각은 함수의 맨 위에서 선언하고 가능한 한 처음 사용하는 것에 가깝다는 것입니다. 둘 다! 그리고이를 수행하는 방법은 잘 나누어 진 서브 루틴을 사용하는 것입니다.
그러나 긴 기능을 사용하는 경우 메소드를 추출하는 것이 더 쉽기 때문에 처음 사용하는 것에 가장 가까운 것을 넣으십시오.
내 레시피는 이것입니다. 모든 지역 변수의 경우 변수를 가져 와서 선언을 맨 아래로 이동하고 컴파일 한 다음 선언을 컴파일 오류 바로 앞으로 이동하십시오. 그것은 첫 번째 사용입니다. 모든 지역 변수에 대해이 작업을 수행하십시오.
int foo = 0;
<code that uses foo>
int bar = 1;
<code that uses bar>
<code that uses foo>
이제 선언 전에 시작되는 스코프 블록을 정의하고 프로그램이 컴파일 될 때까지 끝을 이동하십시오.
{
int foo = 0;
<code that uses foo>
}
int bar = 1;
<code that uses bar>
>>> First compilation error here
<code that uses foo>
foo를 사용하는 코드가 더 있으므로 컴파일되지 않습니다. 우리는 컴파일러가 foo를 사용하지 않기 때문에 bar를 사용하는 코드를 통과 할 수 있음을 알 수 있습니다. 이 시점에서 두 가지 선택이 있습니다. 기계적인 방법은 컴파일 할 때까지 “}”를 아래쪽으로 옮기는 것이고, 다른 방법은 코드를 검사하고 순서를 다음과 같이 바꿀 수 있는지 확인하는 것입니다.
{
int foo = 0;
<code that uses foo>
}
<code that uses foo>
int bar = 1;
<code that uses bar>
주문을 전환 할 수 있다면 임시 값의 수명이 단축되기 때문에 원하는 것일 수 있습니다.
주목해야 할 또 다른 사항은 foo의 값을 사용하는 코드 블록 사이에서 foo의 값을 유지해야하는지 또는 둘 다에서 다른 foo 일 수 있다는 것입니다. 예를 들어
int i;
for(i = 0; i < 8; ++i){
...
}
<some stuff>
for(i = 3; i < 32; ++i){
...
}
이러한 상황은 내 절차보다 더 필요합니다. 개발자는 코드를 분석하여 수행 할 작업을 결정해야합니다.
그러나 첫 번째 단계는 첫 번째 사용법을 찾는 것입니다. 시각적으로 할 수는 있지만 때로는 선언을 삭제하고 컴파일하고 첫 번째 사용 위에 다시 넣는 것이 더 쉽습니다. 첫 번째 사용이 if 문 안에 있으면 그것을 넣고 컴파일하는지 확인하십시오. 그러면 컴파일러는 다른 용도를 식별합니다. 두 용도를 모두 포함하는 스코프 블록을 만드십시오.
이 기계적인 부분이 끝나면 데이터의 위치를 분석하기가 더 쉬워집니다. 변수가 큰 범위 블록에서 사용되는 경우 상황을 분석하고 두 개의 다른 항목에 대해 동일한 변수를 사용하고 있는지 확인하십시오 (예 : “i”와 같이 두 개의 for 루프에 사용됨). 용도와 관련이없는 경우, 관련없는 용도마다 새 변수를 작성하십시오.
답변
함수에서 맨 위 또는 “로컬”로 모든 변수를 선언해야합니다. 정답은:
사용하는 시스템 종류에 따라 다릅니다 .
1 / 내장형 시스템 (특히 비행기 또는 자동차와 같은 생활과 관련됨) : 동적 메모리 (예 : calloc, malloc, new …)를 사용할 수 있습니다. 1000 명의 엔지니어와 함께 매우 큰 프로젝트를 수행한다고 가정 해보십시오. 새로운 동적 메모리를 할당하고 더 이상 사용하지 않는 경우 제거하지 않은 경우 어떻게합니까? 내장 시스템이 장시간 실행되면 스택 오버플로가 발생하고 소프트웨어가 손상됩니다. 품질을 확인하기 쉽지 않습니다 (가장 좋은 방법은 동적 메모리 금지).
비행기가 30 일 안에 운행되고 꺼지지 않으면 소프트웨어가 손상된 경우 (비행기가 여전히 공중에있을 때) 어떻게됩니까?
2 / 웹, PC와 같은 다른 시스템 (메모리 공간이 큼) :
사용하는 메모리를 최적화하려면 변수를 “로컬로”선언해야합니다. 이러한 시스템이 오랫동안 실행되고 스택 오버플로가 발생하는 경우 (다른 사람이 동적 메모리 제거를 잊었 기 때문에) PC를 재설정하는 간단한 작업 만 수행하십시오 .P 삶에 영향을 미치지 않습니다.