문제

이 질문에는 이미 답변이 있습니다.

for 루프 문에서 사용되는 것을 볼 수 있지만 어디에서나 유효한 구문입니다.다른 곳에서 어떤 용도를 찾았습니까?

도움이 되었습니까?

해결책

C 언어 (C ++)는 역사적으로 완전히 다른 두 가지 프로그래밍 스타일이 혼합되어 있으며, "명령문 프로그래밍"및 "표현 프로그래밍"이라고 할 수 있습니다. 아시다시피, 모든 절차 적 프로그래밍 언어는 일반적으로 다음과 같은 기본 구성을 지원합니다. 시퀀싱 그리고 분기 (보다 구조화 된 프로그래밍). 이러한 기본 구성은 C/C ++ 언어로 두 가지 형태로 제공됩니다. 하나는 명령문 프로그래밍 용, 다른 하나는 Expression Programming 용입니다.

예를 들어, 진술의 관점에서 프로그램을 작성하면 분리 된 일련의 진술을 사용할 수 있습니다. ;. 분기를하고 싶을 때 사용합니다. if 진술. 사이클 및 기타 종류의 제어 전송 문을 사용할 수도 있습니다.

표현 프로그래밍에서 동일한 구성도 제공합니다. 이것은 실제로 어디에 있습니다 , 운영자가 작용합니다. 운영자 , C, IE 연산자의 순차적 표현의 분리기 외에는 아무것도 없습니다. , 발현 프로그래밍에서는 동일한 역할을합니다 ; 명세서 프로그래밍에서. 표현 프로그래밍 분기는 이루어집니다 ?: 연산자 및 또는 또는 단락 평가 특성을 통해 && 그리고 || 운영자. (표현 프로그래밍은 사이클이 없습니다. 그리고이를 재귀로 대체하려면 명세서 프로그래밍을 적용해야합니다.)

예를 들어 다음 코드입니다

a = rand();
++a;
b = rand();
c = a + b / 2;
if (a < c - 5)
  d = a;
else
  d = b;

이는 전통적인 진술 프로그래밍의 예이며, 표현 프로그래밍 측면에서 다시 작성할 수 있습니다.

a = rand(), ++a, b = rand(), c = a + b / 2, a < c - 5 ? d = a : d = b;

또는 AS

a = rand(), ++a, b = rand(), c = a + b / 2, d = a < c - 5 ? a : b;

또는

d = (a = rand(), ++a, b = rand(), c = a + b / 2, a < c - 5 ? a : b);

또는

a = rand(), ++a, b = rand(), c = a + b / 2, (a < c - 5 && (d = a, 1)) || (d = b);

말할 필요도없이, 실제 명령문 프로그래밍에서는 일반적으로 훨씬 더 읽기 쉬운 C/C ++ 코드를 생성하므로 일반적으로 매우 잘 측정되고 제한된 양으로 표현식 프로그래밍을 사용합니다. 그러나 많은 경우에 그것은 편리합니다. 그리고 받아 들일 수있는 것과 그렇지 않은 것 사이의 경계는 개인적 취향과 확립 된 관용구를 인식하고 읽는 능력의 문제입니다.

추가 참고 사항 : 언어의 디자인은 명백히 진술에 맞게 조정됩니다. 진술은 표현을 자유롭게 호출 할 수 있지만 표현은 진술을 호출 할 수 없습니다 (사전 정의 된 함수를 호출하는 것 외에는). 이 상황은 소위 호출을 지원하는 GCC 컴파일러에서 다소 흥미로운 방식으로 변경됩니다. "진술 표현" 확장으로 (표준 C에서 "표현 문"에 대칭). "명령문 표현"은 표준 C의 명령문에 표현식 기반 코드를 삽입 할 수있는 것처럼 사용자가 명령문 기반 코드를 표현식에 직접 삽입 할 수 있습니다.

또 다른 추가 참고 사항 : C ++ 언어 Functor 기반 프로그래밍은 중요한 역할을하며, 이는 다른 형태의 "표현 프로그래밍"으로 볼 수 있습니다. C ++ 설계의 현재 추세에 따르면, 많은 상황에서 전통적인 진술 프로그래밍보다 바람직한 것으로 간주 될 수 있습니다.

다른 팁

나는 일반적으로 C의 쉼표가 단순히 사용하기에 좋은 스타일이 아니라고 생각합니다. 다른 사람이 코드를 읽고/이해/수정하려고하는 다른 사람에 의해 또는 한 달 동안 자신의 한 달이 지났습니다. 변수 선언을 벗어나고 루프의 경우, 물론 이는 관용적입니다.

예를 들어, 여러 문장을 3 배 연산자 (? :), ALA에 포장하는 데 사용할 수 있습니다.

int x = some_bool ? printf("WTF"), 5 : fprintf(stderr, "No, really, WTF"), 117;

하지만 내 신들, 왜?!? (실제 코드에서 이런 식으로 사용되는 것을 보았지만 불행히도 표시 할 수있는 액세스 권한이 없습니다)

매크로가 함수 인 척하고 값을 반환하고 싶어하지만 다른 작업을 먼저 해야하는 매크로에서 사용되는 것을 보았습니다. 항상 추악하고 종종 위험한 해킹처럼 보입니다.

단순화 된 예 :

#define SomeMacro(A) ( DoWork(A), Permute(A) )

여기 B=SomeMacro(A) Permute (a)의 결과를 "반환"하고 "b"에 할당합니다.

C ++의 2 개의 킬러 쉼표 운영자 기능 :

a) 특정 문자열이 발생할 때까지 스트림에서 읽으십시오 (코드를 건조시키는 데 도움이) :

 while (cin >> str, str != "STOP") {
   //process str
 }

b) 생성자 이니셜 라이저에 복잡한 코드 작성 :

class X : public A {
  X() : A( (global_function(), global_result) ) {};
};

메시지를 보내기 위해 뮤 테스 잠금 장치를 디버깅하기 위해 쉼표를 사용해야했습니다. ~ 전에 자물쇠가 기다리기 시작합니다.

파생 된 잠금 생성자 본문의 로그 메시지를 할 수 없었으므로 초기화 목록에서 BaseClass (( "Message"), 실제_arg)를 사용하여 기본 클래스 생성자의 인수에 넣어야했습니다. 추가 괄호를 주목하십시오.

다음은 수업의 추출물입니다.

class NamedMutex : public boost::timed_mutex
{
public:
    ...

private:
    std::string name_ ;
};

void log( NamedMutex & ref__ , std::string const& name__ )
{
    LOG( name__ << " waits for " << ref__.name_ );
}

class NamedUniqueLock : public boost::unique_lock< NamedMutex >
{
public:

    NamedUniqueLock::NamedUniqueLock(
        NamedMutex & ref__ ,
        std::string const& name__ ,
        size_t const& nbmilliseconds )
    :
        boost::unique_lock< NamedMutex >( ( log( ref__ , name__ ) , ref__ ) ,
            boost::get_system_time() + boost::posix_time::milliseconds( nbmilliseconds ) ),
            ref_( ref__ ),
            name_( name__ )
    {
    }

  ....

};

그만큼 과제를 향상시킵니다 라이브러리는 유용하고 읽기 쉬운 방식으로 쉼표 연산자를 과부하시키는 좋은 예입니다. 예를 들어:

using namespace boost::assign;

vector<int> v; 
v += 1,2,3,4,5,6,7,8,9;

C 표준에서 :

쉼표 연산자의 왼쪽 피연산자는 무효 표현으로 평가됩니다. 평가 후 시퀀스 지점이 있습니다. 그런 다음 오른쪽 피연산자가 평가됩니다. 결과에는 유형과 가치가 있습니다. (쉼표 연산자는 lvalue를 산출하지 않습니다.))) 쉼표 연산자의 결과를 수정하거나 다음 시퀀스 지점 후에 액세스하려는 시도가 이루어지면 동작이 정의되지 않습니다.

간단히 말해서 C는 하나만 기대하는 표현식을 지정할 수 있습니다. 그러나 실제로는 대부분 루프에 사용됩니다.

주목하십시오 :

int a, b, c;

쉼표 운영자가 아니며 선언자 목록입니다.

때로는 다음과 같은 디버그 매크로와 같은 매크로에서 사용됩니다.

#define malloc(size) (printf("malloc(%d)\n", (int)(size)), malloc((size)))

(근데 봐봐 이 끔찍한 실패, 정말로 당신의 것입니다. 당신이 그것을 과도하게 사용하면 어떤 일이 일어날 수 있습니까?)

그러나 정말로 필요하지 않거나 코드를 더 읽기 쉽고 유지 관리하기 쉽게 만드는 것이 확실하지 않은 경우에는 쉼표 연산자를 사용하지 않는 것이 좋습니다.

이 질문에 "C ++"태그가있는 한 과부하 할 수 있습니다. 나는 과부하 된 쉼표가 행렬을 생성하는 데 사용되는 코드를 보았습니다. 또는 벡터, 나는 정확히 기억하지 못한다. 예쁘지 않아요 (조금 혼란 스럽지만) :

Myvector foo = 2, 3, 4, 5, 6;

루프 외에는 코드 냄새의 향기가있을 수 있습니다. 쉼표 운영자에게 잘 사용되는 유일한 곳은 다음과 같습니다.

 delete p, p = 0;

대안에 대한 유일한 값은 두 줄에있는 경우이 작업의 절반 만 모방/붙여 넣을 수 있다는 것입니다.

나는 또한 당신이 그것을 습관에서 벗어나면 제로 할당을 결코 잊지 못할 것이기 때문에 나는 그것을 좋아한다. (물론 P가 Auto_ptr, Smart_ptr, Shared_ptr 등의 신경 안에 있지 않은 이유는 다른 질문입니다.)

표준에서 @nicolas Goy의 인용이 주어지면 다음과 같은 루프에 대한 하나의 라이너를 쓸 수있는 것처럼 들립니다.

int a, b, c;
for(a = 0, b = 10; c += 2*a+b, a <= b; a++, b--);
printf("%d", c);

하지만 좋은 신, 남자, 당신은 정말로 당신의 C 코드를 만들고 싶습니까? 이런 식으로 모호합니까?

일반적으로 Comma 연산자는 코드를 덜 읽기 쉽게 만들기 때문에 사용하지 않습니다. 거의 모든 경우에 두 가지 진술을하는 것이 더 단순하고 명확합니다. 처럼:

foo=bar*2, plugh=hoo+7;

명확한 이점을 제공하지 않습니다.

foo=bar*2;
plugh=hoo+7;

내가 그것을 사용한 루프 이외의 한 곳은 if/else constructs, like에서 다음과 같습니다.

if (a==1)
... do something ...
else if (function_with_side_effects_including_setting_b(), b==2)
... do something that relies on the side effects ...

기능을 IF 전에 넣을 수 있지만 기능을 실행하는 데 시간이 오래 걸리면 필요하지 않은 경우 수행하지 않아도됩니다. 옵션. 대안은 IF가 추가 레이어를 중첩하는 것입니다. 위의 코드는 약간 비밀이기 때문에 실제로 내가하는 일입니다. 그러나 나는 지금 그것을 쉼표로했고 그 다음에 둥지도 암호이기 때문에 그것을했습니다.

해설을 추가하는 데 매우 유용합니다 ASSERT 매크로 :

ASSERT(("This value must be true.", x));

대부분의 주장 스타일 매크로는 주장의 전체 텍스트를 출력 할 것이므로, 이는 어설 션에 유용한 정보를 추가로 추가합니다.

나는 종종 클래식 싱글 톤의 게으른 초기화 문제를 피하기 위해 일부 CPP 파일에서 정적 이니셜 라이저 기능을 실행하는 데 종종 사용합니다.

void* s_static_pointer = 0;

void init() {
    configureLib(); 
    s_static_pointer = calculateFancyStuff(x,y,z);
    regptr(s_static_pointer);
}

bool s_init = init(), true; // just run init() before anything else

Foo::Foo() {
  s_static_pointer->doStuff(); // works properly
}

나에게 C의 쉼표와 함께 정말 유용한 경우는 조건부로 무언가를 수행하기 위해 그것들을 사용하는 것입니다.

  if (something) dothis(), dothat(), x++;

이것은 동일합니다

  if (something) { dothis(); dothat(); x++; }

이것은 "타이핑"에 관한 것이 아니라 때로는 매우 명확 해 보입니다.

또한 루프는 다음과 같습니다.

while(true) x++, y += 5;

물론 둘 다 루프의 조건부 부품 또는 실행 가능한 부분이 매우 작고 2-3 개의 작업 일 때만 유용 할 수 있습니다.

내가 본 유일한 시간 , 외부에서 사용되는 연산자 for 루프는 제 3의 진술에서 분석을 수행하는 것이 었습니다. 오래 전부터 정확한 진술을 기억할 수는 없지만 다음과 같습니다.

int ans = isRunning() ? total += 10, newAnswer(total) : 0;

분명히 제정신 인 사람은 이와 같은 코드를 쓸 수는 없지만 저자는 가독성이 아니라 생성 한 어셈블러 코드를 기반으로 C 진술을 구성하는 사악한 천재였습니다. 예를 들어, 그는 때때로 생성 된 어셈블러를 선호했기 때문에 IF 진술 대신 루프를 사용했습니다.

그의 코드는 매우 빠르지 만 인재 할 수 없었습니다. 더 이상 작업 할 필요가 없어서 기쁩니다.

매크로에 사용하여 "Char*가 가리키는 출력 버퍼에 모든 유형의 값을 할당 한 다음 필요한 수의 바이트 수로 포인터를 증가 시켰습니다."

#define ASSIGN_INCR(p, val, type)  ((*((type) *)(p) = (val)), (p) += sizeof(type))

쉼표 연산자를 사용하면 매크로가 표현식 또는 원하는 진술에 사용할 수 있음을 의미합니다.

if (need_to_output_short)
    ASSIGN_INCR(ptr, short_value, short);

latest_pos = ASSIGN_INCR(ptr, int_value, int);

send_buff(outbuff, (int)(ASSIGN_INCR(ptr, last_value, int) - outbuff));

반복적 인 타이핑이 줄어들었지만 너무 읽을 수없는 조심해야합니다.

이 답변의 과도한 버전을 참조하십시오 여기.

"코드 골프"에 유용할 수 있습니다.

코드 골프:큐브 플레이

그만큼 , ~에 if(i>0)t=i,i=0; 두 문자를 저장합니다.

QEMU는 루프 용 조건부 부분 내에서 쉼표 연산자를 사용하는 코드가 있습니다 ( qtailq_foreach_safe qemu-queue.h). 그들이 한 일은 다음으로 요약됩니다.

#include <stdio.h>

int main( int argc, char* argv[] ){
  int x = 0, y = 0;

  for( x = 0; x < 3 && (y = x+1,1); x = y ){
    printf( "%d, %d\n", x, y );
  }

  printf( "\n%d, %d\n\n", x, y );

  for( x = 0, y = x+1; x < 3; x = y, y = x+1 ){
    printf( "%d, %d\n", x, y );
  }

  printf( "\n%d, %d\n", x, y );
  return 0;
}

... 다음 출력으로 :

0, 1
1, 2
2, 3

3, 3

0, 1
1, 2
2, 3

3, 4

이 루프의 첫 번째 버전에는 다음과 같은 효과가 있습니다.

  • 두 가지 할당을 피하기 때문에 코드가 동기화되지 않을 가능성이 줄어 듭니다.
  • 사용하기 때문에 &&, 과제는 마지막 반복 후에 평가되지 않습니다.
  • 과제는 평가되지 않기 때문에 끝에있을 때 (위의 코드가 아닌 QEMU의 코드에서) 큐의 다음 요소를 참조하려고 시도하지 않습니다.
  • 루프 내부에는 현재 및 다음 요소에 액세스 할 수 있습니다.

배열 초기화에서 찾았습니다.

C에서 {} 대신 이중 치수 배열을 초기화하기 위해 ()를 사용하면 정확히 어떻게됩니까?

배열을 초기화 할 때 a[][]:

int a[2][5]={(8,9,7,67,11),(7,8,9,199,89)};

그런 다음 배열 요소를 표시합니다.

나는 얻다:

11 89 0 0 0 
0 0 0 0 0
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top