programing

C 콤마 연산자 사용

goodsources 2022. 7. 17. 18:21
반응형

C 콤마 연산자 사용

에서 loop 문장으로 사용되고 있는 것을 알 수 있습니다만, 이것은 어디에서나 유효한 구문입니다.만약 있다면 다른 곳에서 무슨 소용이 있습니까?

C++뿐만 아니라 C 언어도 역사적으로 완전히 다른 두 가지 프로그래밍 스타일이 혼합되어 있으며, 이를 "스테이트먼트 프로그래밍"과 "표현식 프로그래밍"이라고 할 수 있습니다.아시다시피 모든 절차 프로그래밍 언어는 일반적으로 시퀀스 및 분기 같은 기본 구조를 지원합니다(구조화된 프로그래밍 참조).이러한 기본 구성 요소는 두 가지 형태로 C/C++ 언어로 나타납니다. 하나는 문 프로그래밍용이고 다른 하나는 표현식 프로그래밍용입니다.

를 들어,할 수 .;는 '브런치를 사용합니다.if도 있습니다.또한 사이클 및 기타 종류의 제어 전송 문을 사용할 수도 있습니다.

표현식 프로그래밍에서는 동일한 구성도 사용할 수 있습니다. '아예'가 있는 곳이에요.,오퍼레이터가 활동을 개시합니다. ★★★★★★★★★★★★★★★」,순차적 즉 연산자 C의 순차적 입니다.,은 현에서 in in in in in in in in in in in 와 같은 역할을 합니다.;는 스테이트먼트 프로그래밍에서 사용합니다.는 표현 프로그래밍을 통해 .?:및 다른 평가 을 통해 '단락 '를 합니다.&& ★★★★★★★★★★★★★★★★★」||연산자(단, 표현식 프로그래밍에는 주기가 없습니다.또한 재귀로 대체하려면 문 프로그래밍을 적용해야 합니다.)

예를 들어 다음 코드

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;

또는 로서

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 컴파일러에서 상당히 흥미로운 방법으로 변경되며, GCC 컴파일러는 확장(표준 C의 "표현문"과 대칭)으로 소위 "표현식"을 지원합니다."스테이트먼트 표현식"을 사용하면 표현식 기반 코드를 표준 C의 문에 삽입할 수 있는 것과 마찬가지로 사용자가 직접 표현식에 삽입할 수 있습니다.

또 다른 주의사항: C++ 언어 함수 기반 프로그래밍은 중요한 역할을 하며, 이는 "표현식 프로그래밍"의 또 다른 형태로 볼 수 있습니다.C++ 설계의 현재 동향에 따르면 많은 상황에서 기존의 문장 프로그래밍보다 선호될 수 있습니다.

C++의 2개의 킬러 콤마 연산자 기능:

a) 특정 문자열이 발생할 때까지 스트림에서 읽습니다(코드 DRY를 유지하는 데 도움이 됩니다).

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

b) 컨스트럭터 이니셜라이저에 복잡한 코드를 작성합니다.

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

일반적으로 C의 콤마는 단순히 코드를 읽거나 이해하거나 수정하려는 다른 사람에 의해 또는 한 달 후에 당신 자신이 놓치기 쉽기 때문에 좋은 스타일이 아니라고 생각합니다.변수 선언의 외부 및 루프의 경우, 물론 관용적인 경우입니다.

예를 들어, 여러 문을 3진 연산자(?:), ala:로 묶기 위해 사용할 수 있습니다.

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

하지만 세상에, 왜?(실제 코드에서 이 방법으로 사용되고 있는 것을 보았습니다만, 유감스럽게도 이 코드에 액세스 할 수 없습니다.)

Boost Assignment 라이브러리는 편리하고 읽기 쉬운 방법으로 쉼표 연산자를 오버로드하는 좋은 예입니다.예를 들어 다음과 같습니다.

using namespace boost::assign;

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

이것은 코멘트를 추가할 때 매우 유용합니다.ASSERT★★★★★★★★★★★★★★★★★★:

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

대부분의 아사트 스타일 매크로는 인수의 텍스트 전체를 출력하기 때문에 이 경우 어설션에 유용한 정보가 추가됩니다.

매크로가 함수로 가장하여 값을 반환하고 싶지만 다른 작업을 먼저 수행해야 하는 매크로에서 사용되는 것을 본 적이 있습니다.그것은 항상 못생기고 종종 위험한 해킹처럼 보인다.

간단한 예:

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

서 ★★★★B=SomeMacro(A)permute(A)는 "B"로 해주세요.

일반적으로 콤마 연산자는 코드를 읽기 어렵게 하기 때문에 사용하지 않습니다.거의 모든 경우, 두 가지 진술만 하는 것이 더 간단하고 명확할 것입니다.예를 들어 다음과 같습니다.

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

에서는, 다음과 같은 명확한 메리트는 없습니다.

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

루프 외에 if/else 구조에 사용한 유일한 장소:

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 앞에 함수를 둘 수도 있지만, 함수가 실행되는 데 시간이 오래 걸린다면 불필요한 경우, a!=1이 아니면 함수가 수행되지 않아야 하는 경우, 그것은 선택사항이 아닙니다.또 다른 방법은 IF를 추가 레이어로 중첩하는 것입니다.위의 코드는 조금 이해하기 어렵기 때문에 실제로 그렇게 하고 있습니다.하지만 가끔 쉼표 방식으로 합니다. 둥지도 복잡하기 때문입니다.

잠금이 시작되기 전에 메시지를 넣기 위해 쉼표를 사용하여 mutex 잠금을 디버깅해야 했습니다.

파생된 잠금 생성자 본문에 있는 로그 메시지 외에는 할 수 없었기 때문에 초기화 목록에서 : baseclass("message")를 사용하여 기본 클래스 생성자의 인수에 넣어야 했습니다.여분의 괄호에 주의해 주세요.

다음은 클래스의 발췌입니다.

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__ )
    {
    }

  ....

};

C 표준부터:

쉼표 연산자의 왼쪽 피연산자는 void 식으로서 평가됩니다.평가 후에 시퀀스 포인트가 있습니다.그런 다음 오른쪽 피연산자가 평가됩니다. 결과에는 피연산자의 유형과 값이 포함됩니다.(콤마 연산자는 l값을 산출하지 않습니다).콤마 연산자의 결과를 수정하거나 다음 시퀀스 포인트 이후에 액세스하려고 하면 동작은 정의되지 않습니다.

즉, C가 1개만 기대하는 식을 여러 개 지정할 수 있습니다.하지만 실제로는 대부분 루프에 사용됩니다.

주의:

int a, b, c;

쉼표 연산자가 아니라 선언자 목록입니다.

다음과 같은 디버깅 매크로에서 사용되는 경우가 있습니다.

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

(하지만 이 끔찍한 실패를 실제로 보세요. 너무 무리하면 어떤 일이 일어날 수 있는지 말입니다.)

단, 꼭 필요한 경우나 코드의 가독성과 유지보수가 용이하다고 확신하지 않는 한 콤마 연산자를 사용하지 않는 것이 좋습니다.

오버로드 할 수 있습니다(이 질문에 "C++" 태그가 붙어 있는 경우).행렬 생성에 오버로드된 쉼표가 사용된 코드를 본 적이 있습니다.아니면 벡터인지 정확히 기억은 안 나네요.예쁘죠? (좀 헷갈리긴 하지만)

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

for 루프 밖에서는 코드 냄새가 날 수 있습니다.쉼표 연산자의 좋은 사용처는 삭제의 일부로서 밖에 없습니다.

 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코드를 좀 더 모호하게 만들고 싶어?

일부 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;

물론 두 가지 모두 루프의 조건부 부분 또는 실행 가능 부분이 매우 작을 때만 유용합니다.

가 본 건 ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★,에서 for 내의 을 실행하는 입니다.loop은 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;는 2글자를 저장합니다.

qemu에는 for 루프의 조건부 부분 내에서 쉼표 연산자를 사용하는 코드가 있습니다(qemu-queue.h의 QTAILQ_FOREACH_SAFE 참조).그들이 한 일은 다음과 같이 요약된다.

#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

언급URL : https://stackoverflow.com/questions/1613230/uses-of-c-comma-operator

반응형