[c] C에서 효과가없는 진술이 합법적 인 것으로 간주되는 이유는 무엇입니까?

이 질문이 순진한 경우 용서하십시오. 다음 프로그램을 고려하십시오.

#include <stdio.h>

int main() {
  int i = 1;
  i = i + 2;
  5;
  i;
  printf("i: %d\n", i);
}

위의 예에서, 진술 5;과는 i;완전히 불필요한 것, 그러나 기본적으로 경고 또는 오류없이 코드 컴파일은 (단, GCC는 던져 않습니다 warning: statement with no effect [-Wunused-value]와 때 실행 된 경고 -Wall). 그들은 프로그램의 나머지 부분에 영향을 미치지 않으므로 왜 처음부터 유효한 진술로 간주됩니까? 컴파일러는 단순히 그것들을 무시합니까? 그러한 진술을 허용하면 어떤 이점이 있습니까?



답변

이러한 진술을 허용하면 한 가지 장점은 사람이 작성하지 않고 매크로 나 다른 프로그램으로 작성하는 코드에서 비롯됩니다.

예를 들어, int do_stuff(void)성공하면 0을, 실패하면 -1을 반환해야하는 함수 를 상상해보십시오 . “stuff”에 대한 지원은 선택 사항 일 수 있으므로 다음을 수행하는 헤더 파일을 가질 수 있습니다.

#if STUFF_SUPPORTED
#define do_stuff() really_do_stuff()
#else
#define do_stuff() (-1)
#endif

이제 가능하면 일을하고 싶지만 성공 또는 실패 여부를 신경 쓰지 않을 수도있는 코드를 상상해보십시오.

void func1(void) {
    if (do_stuff() == -1) {
        printf("stuff did not work\n");
    }
}

void func2(void) {
    do_stuff(); // don't care if it works or not
    more_stuff();
}

STUFF_SUPPORTED0, 전처리가에 전화를 확장됩니다 func2단지 읽기하는 문

    (-1);

그래서 컴파일러 패스는 당신을 귀찮게하는 일종의 “불필요한”진술을 보게 될 것입니다. 또 다른 무엇을 할 수 있습니까? 의 경우 #define do_stuff() // nothing코드 입력 func1이 중단됩니다. (그리고 당신은 여전히 더 불필요하게 func2읽는 빈 문장을 갖게 ;될 것입니다.) 반면에, do_stuff()-1을 반환 하는 함수 를 실제로 정의 해야하는 경우 함수 호출 비용이 발생할 수 있습니다 아무 이유없이.


답변

C의 간단한 문장은 세미콜론으로 끝납니다.

C의 간단한 문장은 표현식입니다. 표현식은 변수, 상수 및 연산자의 조합입니다. 모든 표현식은 변수에 할당 할 수있는 특정 유형의 값을 가져옵니다.

일부 “스마트 컴파일러”는 5를 버릴 수 있다고 말했다. 그리고 나; 진술.


답변

효력이없는 진술은 허용하는 것보다 금지하는 것이 더 어렵 기 때문에 허용됩니다. 이것은 C가 처음 설계되고 컴파일러가 더 작고 단순 할 때 더 관련이있었습니다.

표현 문은 세미콜론 다음 식으로 구성되어 있습니다. 동작은 표현식을 평가하고 결과 (있는 경우)를 버리는 것입니다. 일반적으로 표현의 평가에는 부작용이 있지만 주어진 표현에 부작용이 있는지 여부를 결정하는 것이 항상 쉬운 것은 아닙니다.

예를 들어, 함수 호출은 표현식이므로 세미콜론 다음에 오는 함수 호출은 명령문입니다. 이 진술에 부작용이 있습니까?

some_function();

의 구현을 보지 않고는 말할 수 없습니다 some_function.

이건 어때요?

obj;

아마도 그렇지는 않지만- obj로 정의 되면 volatile그렇게됩니다.

허가 어떤 로 만들어 질 식 표현 문을 세미콜론을 추가하면 언어 정의 간단합니다. 식에 부작용이 필요하면 언어 정의와 컴파일러에 복잡성이 추가됩니다. C는 일관된 규칙 세트 (함수 호출은 표현식, 할당은 표현식, 세미콜론 뒤에 오는 표현식)를 기반으로하며 프로그래머가 이해할 수 있거나 이해할 수없는 일을 방해하지 않으면 서 원하는 것을 수행 할 수 있도록합니다.


답변

아무런 영향을 미치지 않고 나열한 명령문은 표현식 명령문의 예제이며 구문은 C 표준의 6.8.3p1 섹션에 다음과 같이 제공됩니다.

 expression-statement :
    expression opt  ;

섹션 6.5의 모든 표현의 정의에 전념하지만, 느슨하게 말하고 표현하는 상수와 연산자와 연결 식별자로 구성되어 있습니다. 특히 표현식은 대입 연산자를 포함하거나 포함하지 않을 수 있으며 함수 호출을 포함하거나 포함하지 않을 수 있습니다.

그래서 어떤 표현 식 문으로 세미콜론 자격을 하였다. 실제로, 코드의 각 행은 표현식 문의 예입니다.

i = i + 2;
5;
i;
printf("i: %d\n", i);

일부 연산자에는 할당 연산자 세트 및 사전 / 사후 증분 / 감소 연산자와 같은 부작용 () 있으며 함수 호출 연산자 문제의 기능에 따라 부작용 있을 있습니다. 그러나 운영자 중 하나가 부작용을 가져야 할 필요는 없습니다.

또 다른 예는 다음과 같습니다.

atoi("1");

이것은 printf예제 의 호출 과 printf마찬가지로 함수를 호출 하고 결과를 삭제 하지만 함수 호출 자체 와 달리 부작용이 없습니다.


답변

때때로 그러한 진술은 매우 편리합니다.

int foo(int x, int y, int z)
{
    (void)y;   //prevents warning
    (void)z;

    return x*x;
}

또는 참조 매뉴얼에서 레지스터를 읽고 무언가를 아카이브하도록 지시 할 때 (예 : uC 세계에서 매우 일반적인 상황) 플래그를 지우거나 설정하는 경우

#define SREG   ((volatile uint32_t *)0x4000000)
#define DREG   ((volatile uint32_t *)0x4004000)

void readSREG(void)
{
    *SREG;   //we read it here
    *DREG;   // and here
}

https://godbolt.org/z/6wjh_5


답변