문제

무엇을 하는가? , 연산자는 C에서 수행합니까?

도움이 되었습니까?

해결책

표현식:

(expression1,  expression2)

먼저 표현식1이 평가된 다음 표현식2가 평가되고 전체 표현식에 대해 표현식2의 값이 반환됩니다.

다른 팁

나는 다음에서 가장 많이 사용되는 것을 보았습니다. while 루프:

string s;
while(read_string(s), s.len() > 5)
{
   //do something
}

수술을 수행한 다음 부작용을 기반으로 테스트를 수행합니다.다른 방법은 다음과 같이 하는 것입니다.

string s;
read_string(s);
while(s.len() > 5)
{
   //do something
   read_string(s);
}

그만큼 쉼표 연산자 왼쪽 피연산자를 평가하고 결과를 버린 다음 오른쪽 피연산자를 평가하면 결과가 됩니다.그만큼 관용적인 링크에 명시된 대로 사용하는 것은 for 루프를 실행하고 다음 예를 제공합니다.

void rev(char *s, size_t len)
{
  char *first;
  for ( first = s, s += len - 1; s >= first; --s)
      /*^^^^^^^^^^^^^^^^^^^^^^^*/ 
      putchar(*s);
}

그렇지 않으면 많지 않습니다 엄청난 의 용도 쉼표 연산자, 비록 그렇긴 하지만 남용하기 쉽다 읽고 유지하기 어려운 코드를 생성합니다.

로부터 초안 C99 표준 문법은 다음과 같습니다.

expression:
  assignment-expression
  expression , assignment-expression

그리고 단락 2 말한다:

그만큼 쉼표 연산자의 왼쪽 피연산자는 void 표현식으로 평가됩니다. 평가 후에 시퀀스 포인트가 있습니다.그런 다음 오른쪽 피연산자가 평가됩니다.결과에는 해당 유형과 값이 있습니다. 97) 쉼표 연산자의 결과를 수정하거나 다음 시퀀스 포인트 이후에 해당 결과에 액세스하려고 하면 동작이 정의되지 않습니다.

각주 97 말한다:

쉼표 연산자는 lvalue를 생성하지 않음.

이는 다음의 결과에 할당할 수 없음을 의미합니다. 쉼표 연산자.

쉼표 연산자에는 다음이 있다는 점에 유의하는 것이 중요합니다. 가장 낮은 우선순위 따라서 다음을 사용하는 경우가 있습니다. () 예를 들어 다음과 같이 큰 차이를 만들 수 있습니다.

#include <stdio.h>

int main()
{
    int x, y ;

    x = 1, 2 ;
    y = (3,4) ;

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

다음과 같은 출력이 표시됩니다.

1 4

쉼표 연산자는 양쪽에 있는 두 표현식을 하나로 결합하여 둘 다 왼쪽에서 오른쪽 순서로 평가합니다.우변의 값은 전체 표현식의 값으로 반환됩니다. (expr1, expr2) 처럼 { expr1; expr2; } 하지만 당신은 결과를 사용할 수 있습니다 expr2 함수 호출이나 할당에서.

에서 흔히 볼 수 있는 for 다음과 같이 여러 변수를 초기화하거나 유지하는 루프입니다.

for (low = 0, high = MAXSIZE; low < high; low = newlow, high = newhigh)
{
    /* do something with low and high and put new values
       in newlow and newhigh */
}

이 외에도 매크로에서 항상 함께 사용해야 하는 두 가지 작업을 마무리할 때 "분노할 때"라는 다른 경우에만 사용했습니다.네트워크에서 전송하기 위해 다양한 이진 값을 바이트 버퍼에 복사하는 코드가 있었고 포인터는 다음과 같이 유지되었습니다.

unsigned char outbuff[BUFFSIZE];
unsigned char *ptr = outbuff;

*ptr++ = first_byte_value;
*ptr++ = second_byte_value;

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

값이 있던 곳 short또는 int우리는 이렇게 했어요:

*((short *)ptr)++ = short_value;
*((int *)ptr)++ = int_value;

나중에 우리는 이것이 실제로 유효한 C가 아니라는 것을 읽었습니다. (short *)ptr 는 더 이상 l-value가 아니며 증가할 수 없습니다. 하지만 당시 컴파일러에서는 신경쓰지 않았습니다.이 문제를 해결하기 위해 표현식을 두 개로 나눕니다.

*(short *)ptr = short_value;
ptr += sizeof(short);

그러나 이 접근 방식은 모든 개발자가 항상 두 문을 모두 입력해야 한다는 점을 기억해야 했습니다.우리는 출력 포인터, 값 및 값 유형을 전달할 수 있는 함수를 원했습니다.이는 템플릿이 있는 C++가 아닌 C이므로 함수가 임의 유형을 취하도록 할 수 없으므로 매크로를 사용하기로 결정했습니다.

#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));

나는 이러한 예가 좋은 스타일이라고 제안하는 것이 아닙니다!사실 나는 스티브 맥코넬의 말을 기억하는 것 같다. 코드 완성 심지어 쉼표 연산자를 사용하지 말라고 조언합니다. for 고리:가독성과 유지 관리성을 위해 루프는 하나의 변수로만 제어되어야 하며 for 라인 자체에는 루프 제어 코드만 포함되어야 하며 다른 추가 초기화 또는 루프 유지 관리 비트는 포함되어서는 안 됩니다.

여러 문을 평가하게 되지만 마지막 문만 결과 값으로 사용합니다(내 생각에는 rvalue라고 생각합니다).

그래서...

int f() { return 7; }
int g() { return 8; }

int x = (printf("assigning x"), f(), g() );

x는 8로 설정되어야 합니다.

쉼표 연산자는 의미가 없으며 100% 불필요한 기능입니다.이의 주요 용도는 "똑똑해지려고 노력하는 사람들"이므로 (의도하지 않게) 읽을 수 있는 코드를 난독화하는 데 사용됩니다.주요 사용 영역은 for 루프를 난독화하는 것입니다. 예를 들면 다음과 같습니다.

for(int i=0, count=0; i<x; i++, count++)

어디 int i=0, count=0 는 실제로 쉼표 연산자가 아니라 선언 목록입니다(여기서는 이미 혼란스럽습니다). i++, count++ 왼쪽 피연산자를 먼저 평가한 다음 오른쪽 피연산자를 평가하는 쉼표 연산자입니다.쉼표 연산자의 결과는 오른쪽 피연산자의 결과입니다.왼쪽 피연산자의 결과는 삭제됩니다.

그러나 위의 코드는 쉼표 연산자 없이 훨씬 더 읽기 쉬운 방식으로 작성될 수 있습니다.

int count = 0;
for(int i=0; i<x; i++) // readable for loop, no nonsense anywhere
{
  ...
  count++;
}

내가 본 쉼표 연산자의 유일한 실제 용도는 시퀀스 포인트에 대한 인위적인 논의입니다. 쉼표 연산자는 왼쪽 피연산자와 오른쪽 피연산자의 평가 사이에 시퀀스 포인트를 제공하기 때문입니다.

따라서 다음과 같이 정의되지 않은 동작 코드가 있는 경우:

printf("%d %d", i++, i++);

실제로 다음을 작성하여 단순히 지정되지 않은 동작(함수 매개변수 평가 순서)으로 바꿀 수 있습니다.

printf("%d %d", (0,i++), (0,i++));

이제 각 평가 사이에 시퀀스 포인트가 있습니다. i++, 따라서 함수 매개변수의 평가 순서가 지정되지 않은 상태로 남아 있더라도 최소한 프로그램이 더 이상 충돌하거나 소각될 위험이 없습니다.

물론 실제 애플리케이션에서는 누구도 그러한 코드를 작성하지 않을 것입니다. 이는 C 언어의 시퀀스 포인트에 대한 언어 변호사 토론에만 유용합니다.

쉼표 연산자는 읽기 어려운 코드를 생성한다는 이유로 MISRA-C:2004 및 MISRA-C:2012에서 금지됩니다.

이전 답변에서 언급했듯이 모든 명령문을 평가하지만 마지막 명령문을 표현식 값으로 사용합니다.개인적으로 나는 이것이 루프 표현식에서만 유용하다는 것을 알았습니다.

for (tmp=0, i = MAX; i > 0; i--)

내가 본 것이 유용하다고 본 유일한 곳은 표현식 중 하나(아마도 init 표현식 또는 루프 표현식)에서 여러 작업을 수행하려는 펑키 루프를 작성할 때입니다.다음과 같은 것 :

bool arraysAreMirrored(int a1[], int a2[], size_t size)
{
  size_t i1, i2;
  for(i1 = 0, i2 = size - 1; i1 < size; i1++, i2--)
  {
    if(a1[i1] != a2[i2])
    {
      return false;
    }
  }

  return true;
}

구문 오류가 있거나 엄격한 C가 아닌 내용을 혼합한 경우 죄송합니다.나는 , 연산자가 좋은 형식이라고 주장하는 것이 아니지만, 그것이 바로 당신이 그것을 사용할 수 있는 이유입니다.위의 경우에는 아마도 while 대신 루프를 실행하면 init 및 루프의 여러 표현식이 더 명확해집니다.(그리고 선언하고 초기화하는 대신 i1과 i2를 인라인으로 초기화했습니다....ㅋ ㅋ ㅋ ㅋ ㅋ ㅋ.)

나는 이것이 최고의 검색 엔진 히트 중 하나이기 때문에 매우 중요하다고 생각하는 @Rajesh 및 @JeffMercado의 질문을 해결하기 위해 이것을 간단히 부활시키고 있습니다.

예를 들어 다음 코드 조각을 살펴보세요.

int i = (5,4,3,2,1);
int j;
j = 5,4,3,2,1;
printf("%d %d\n", i , j);

인쇄됩니다

1 5

그만큼 i 사례는 대부분의 답변에 설명된 대로 처리됩니다.모든 표현식은 왼쪽에서 오른쪽 순서로 평가되지만 마지막 표현식만 할당됩니다. i.결과는 ( 표현 )is1`.

그만큼 j 케이스는 이후 다른 우선순위 규칙을 따릅니다. , 연산자 우선순위가 가장 낮습니다.이러한 규칙으로 인해 컴파일러는 할당 표현식, 상수, 상수 ....표현식은 다시 왼쪽에서 오른쪽 순서로 평가되며 부작용은 계속 표시됩니다. j ~이다 5 결과적으로 j = 5.

흥미롭게도, int j = 5,4,3,2,1; 언어 사양에서는 허용되지 않습니다.안 초기화 기대한다 할당 표현 그래서 직접 , 운영자는 허용되지 않습니다.

도움이 되었기를 바랍니다.

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