C에서 임의의 블록을 관용적으로 사용하는 것은 무엇입니까?


15

블록은 실행될 명령문 목록입니다. C에서 블록이 나타나는 예는 while 문과 if 문 뒤에 있습니다.

while( boolean expression)
    statement OR block

if (boolean expression)
    statement OR block

C는 또한 블록이 블록에 중첩되도록합니다. 변수 이름을 재사용하기 위해 이것을 사용할 수 있습니다. 'x'를 정말로 좋아한다고 가정합니다.

int x = 0;
while (x < 10)
{
    {
        int x = 5;
        printf("%d",x)
    }
    x = x+1;
}

5 번 열 번 인쇄합니다. 변수 이름의 수를 낮추는 것이 바람직한 상황을 볼 수 있다고 생각합니다. 아마도 매크로 확장에 있습니다. 그러나이 기능이 필요한 어려운 이유는 없습니다. 누구든지이 기능이 사용되는 관용구를 제공하여이 기능의 사용을 이해하도록 도울 수 있습니까?


1
솔직히 C 구문을 이해하려고 노력하고 있으며 궁금합니다.
Jonathan Gallagher

C의 정신은 프로그래머를 신뢰하는 것입니다. 프로그래머는 자신의 마음대로 무언가 위대한 것을 만들거나 무언가를 끔찍하게 만들 수 있습니다. 개인적으로, 나는 오버로드 된 변수 이름을 좋아하지 않지만 다른 프로그래머가있을 수 있습니다. 하루가 끝나면 최소한의 버그로 우리가해야 할 일을 완수한다면 ... 왜 논쟁해야합니까?
Fiddling Bits

1
그것이 C에서 얻는 느낌입니다. 나는 언어의 의미론이 괜찮다면 다른 스타일의 코딩을 지원하는 구문을위한 것입니다. 그것은 단지 ... 나는 이것을 보았고 즉각적인 반응은 모든 변수의 이름을 새로운 이름으로 바꾸어 소스에서 소스로 변환을 적용하고 블록을 완전히 평평하게 할 수 있다는 것입니다. 내가 무언가를 제거 할 수 있다고 생각되면, 내가 놓친 것이 있다고 가정합니다.
Jonathan Gallagher

C가 아닌 프로그래머로서 재미있는 타이밍, 나는 오늘 C 코드 에서이 구문을 우연히 발견하고 그것이 무엇인지 궁금했습니다. 물어봐서 다행입니다.
Brandon

답변:


8

아이디어는 변수 이름의 수를 낮게 유지하거나 이름의 재사용을 장려하는 것이 아니라 변수의 범위를 제한하는 것입니다. 당신이 가지고 있다면:

int x = 0;
//...
{
    int y = 3;
    //...
}
//...

y블록 의 범위는 블록으로 제한됩니다. 즉, 블록 전후에 블록을 잊을 수 있습니다. 루프 및 조건과 관련하여 가장 자주 사용되는 것을 볼 수 있습니다. 또한 범위를 벗어나는 변수로 인해 C ++과 같은 C 유사 언어에서 더 자주 볼 수 있습니다.


조건부, 루프 및 함수 본문에서 블록이 자연스럽게 발생한다고 생각합니다. 내가 궁금한 점은 C에서 어디서나 블록을 배치 할 수 있다는 것입니다. C ++에 대한 두 번째 의견은 흥미 롭습니다. 범위를 벗어나면 파괴가 발생한다는 것입니다. 이것은 가비지 수집만을 참조하거나 다음과 같은 다른 용도로 사용됩니까? 별개의 "섹션"이있는 함수 본문을 사용하고 변수 공간의 파괴를 트리거하여 메모리 풋 프린트를 제어하기 위해 블록을 사용할 수 있습니까?
Jonathan Gallagher

1
내가 아는 한, C는 함수의 모든 변수에 대한 모든 메모리를 미리 할당합니다. 그것들이 함수를 통해 스코프를 빠져 나가는 것은 C에서 성능상의 이점이 없을 것이다. 마찬가지로 변수가 스코프에 "때때로"들어가는 것은 함수를 호출하는 동안 메모리 풋 프린트를 바꾸지 않을 것이다.
Gankro

@Gankro 배타적 중첩 범위가 여러 개 있으면 영향을 줄 수 있습니다. 컴파일러는 이러한 각 범위의 변수에 대해 미리 할당 된 고유 한 메모리 청크를 재사용 할 수 있습니다. 물론, 그것은 마음에 오지 않는 이유는 하나의 임의의 범위가 이미 당신은 아마 함수로 추출 할 필요가 사인 인 경우, 두 개 이상의 임의의 범위가 있다는 것입니다 확실히 당신이 리팩토링해야한다는 좋은 지표. 그럼에도 불구하고 스위치 케이스 블록과 같은 것들에서 때때로 제정신의 솔루션으로 나타납니다.
tne

16

예전의 C 시대에는 새로운 블록에서만 새로운 변수를 선언 할 수 있었기 때문입니다.

이런 식으로 프로그래머는 함수를 누설하지 않고 스택 사용을 최소화하지 않고 함수 중간에 새로운 변수를 도입 할 수 있습니다.

오늘날의 옵티 마이저에서는 쓸모가 없으며 자체 기능으로 블록을 추출하는 것을 고려해야한다는 신호입니다.

switch 문에서는 이중 선언을 피하기 위해 사례를 자체 블록으로 묶는 것이 좋습니다.

C ++에서는 예를 들어 RAII 잠금 가드에 유용하며 실행이 범위를 벗어나면서 여전히 중요한 섹션 외부에서 다른 작업을 수행 할 때 소멸자가 릴리스 잠금을 실행하도록 보장합니다.


2
RAII 잠금 장치의 경우 +1 말하자면,이 같은 개념이 루틴의 일부 내에서 큰 스택 버퍼 할당 해제에 유용 할 수 없습니까? 한 번도 해 본 적이 없지만 일부 임베디드 코드에서 확실히 발생할 수있는 것 같습니다.
J Trana

2

나는 그것을 "임의의"블록으로 보지 않을 것이다. 개발자가 사용하기에는 그다지 중요한 기능은 아니지만 C가 블록을 사용하는 방식으로 동일한 의미를 가진 여러 장소에서 동일한 블록 구성을 사용할 수 있습니다. 블록 (C)은 새로운 범위이며,이를 떠나는 변수는 제거됩니다. 블록 사용 방법에 관계없이 균일합니다.

다른 언어에서는 그렇지 않습니다. 이것은 보여 주듯이 남용을 줄일 수 있다는 장점이 있지만, 어떤 맥락에 따라 블록이 다르게 행동한다는 단점이 있습니다.

나는 C 또는 C ++에서 사용되는 독립형 블록을 거의 보지 못했습니다. 종종 큰 구조 또는 연결을 나타내는 객체 또는 파괴하려는 객체가있는 경우가 많습니다. 일반적으로 이것은 함수가 너무 많은 일을하거나 너무 길다는 힌트입니다.


1
불행히도 나는 정기적으로 독립형 블록을 보게됩니다. 거의 모든 경우에 기능이 많은 일을하거나 너무 길기 때문에 거의 모든 경우에 있습니다.
mattnz

또한 C ++에서 독립 실행 형 블록을 정기적으로보고 작성하지만 잠금 및 기타 공유 리소스 주위의 래퍼를 강제로 파괴합니다.
J Trana

2

지금 분명해 보이는 프로그래밍 원칙이 항상 그렇지는 않다는 것을 알아야합니다. C 모범 사례는 예제의 나이에 따라 크게 다릅니다. C가 처음 도입되었을 때 코드를 작은 함수로 나누는 것은 너무 비효율적 인 것으로 간주되었습니다. 데니스 리치 (Dennis Ritchie)는 기본적으로 거짓말을했고 함수 호출은 C에서 실제로 효율적이었다 (그 당시에는 그렇지 않았다).

그것은 이다 가능한 한 작게하여 변수의 범위를 제한하는 오늘날에도 좋은 프로그래밍 연습. 요즘에는 일반적으로 새 함수를 생성하여이를 수행하지만 함수가 비싸다고 생각되면 새 블록을 도입하는 것이 함수 호출의 오버 헤드없이 범위를 제한하는 논리적 방법입니다.

그러나 20 년 전에 C에서 프로그래밍을 시작했습니다. 스코프의 최상위에서 모든 변수를 선언해야했을 때 좋은 스타일로 간주되는 변수 그림자를 기억하지 않습니다. switch 문에서와 같이 두 블록 씩 차례로 다시 선언하지만 섀도 잉은 아닙니다. 아마 변수가 이미 사용 및 특정 이름은 당신이 좋아하는, 호출하고있는 API에 매우 관용적이었다 경우 destsrcstrcpy예를 들어,.


1

임의의 블록은 특별한 계산의 경우에만 사용되는 중간 변수를 도입하는 데 유용합니다.

이것은 숫자 계산 절차가 일반적으로 사용되는 과학 컴퓨팅의 일반적인 패턴입니다.

  1. 많은 매개 변수 또는 중간 수량에 의존합니다.
  2. 특별한 경우를 많이 처리해야합니다.

두 번째 요점 때문에, 임의의 블록을 사용하거나 보조 기능을 도입함으로써 달성되는 제한된 범위의 임시 변수를 도입하는 것이 유용합니다.

보조 기능을 도입하는 것은 맹목적으로 따라야 할 뇌아니 거나 모범 사례 처럼 보일 수 있지만 실제로 는이 특정 상황에서 그렇게하는 이점이 거의 없습니다 .

많은 매개 변수와 중간 수량이 있기 때문에 보조 기능에 전달하는 구조를 도입하려고합니다.

그러나 우리는 우리의 관행에 따르기를 원하기 때문에 하나의 보조 기능 만 도입하는 것이 아니라 여러 가지 기능을 도입 할 것입니다. 따라서 각 함수마다 매개 변수를 전달하는 임시 구조를 소개합니다. 매개 변수를 앞뒤로 이동하기 위해 많은 코드 오버 헤드가 도입되거나 모든 변수를 포함하지만 다음과 같이 보이는 모든 워크 시트 구조를 규칙 화합니다. 일관성이없는 비트의 집합. 언제든지 매개 변수의 절반 만 흥미로운 의미를 갖습니다.

따라서 이러한 보조 구조는 일반적으로 번거롭고 사용하는 것은 코드 팽창 중에서 선택하거나 범위가 너무 넓어서 프로그램의 의미를 약화시키지 않고 추상화하는 것을 의미합니다. .

보조 기능을 도입하면 더 세밀한 테스트 세분성을 도입하여 프로그램의 단위 테스트를 용이하게 할 수 있지만 낮은 수준의 프로 시저와 회귀 테스트가 숫자 트레이스의 숫자 추적과 비교되는 방식 (numdiff 포함)이 아닌지에 대한 단위 테스트를 결합 하여 동일한 작업을 수행 할 수 있습니다. .


0

일반적으로 이러한 방식으로 변수 이름을 재사용하면 향후 코드 리더에게 혼동을 줄 수 있습니다. 내부 변수의 이름을 다른 이름으로 지정하는 것이 좋습니다. 실제로 C # 언어는 이러한 방식으로 변수를 사용할 수 없습니다.

매크로 확장에서 중첩 블록을 사용하는 것이 변수 이름 충돌을 방지하는 데 어떻게 유용한 지 알 수있었습니다.


0

일반적으로 해당 수준에서 범위가없는 것들을 범위 지정하기위한 것입니다. 이것은 매우 드문 일이며 일반적으로 리팩토링이 더 나은 선택이지만 과거에는 switch 문에서 한두 번 실행했습니다.

switch(foo) {
   case 1:
      {
         // bar
      }
   case 2:
   case 3:
      // baz
      break;
   case 4:
   case 5:
      // bang
      break;
}

유지 보수를 고려할 때 리팩토링은 각 구현이 몇 줄에 불과한 한 모든 구현을 한 행에 두는 것과 균형을 이루어야합니다. 함수 이름 목록보다는 모두 함께 사용하는 것이 더 쉬울 수 있습니다.

필자의 경우, 올바르게 기억한다면 대부분의 경우는 동일한 코드의 약간의 변형이었습니다. 단 하나의 코드는 여분의 전처리만으로 다른 코드와 동일하다는 점만 다릅니다. 스위치는 코드를 작성하는 가장 간단한 형식이었으며 추가 범위는 추가 로컬 변수를 사용할 수있게했으며 추가 사례에서 염려 할 필요가 없었습니다 (예 : 변수 이름이 실수로 스위치 전에 정의 된 변수와 겹치지 만 나중에 사용).

switch 문은 단순히 내가 사용한 것을 사용한다는 점에 유의하십시오. 나는 그것이 다른 곳에서도 적용될 수 있다고 확신하지만, 그것들이 효과적으로 그렇게 사용 된 것을 본 적이 없습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.