절대 실행되지 않는 코드가 정의되지 않은 동작을 호출할 수 있습니까?
정의되지 않은 동작(이 예에서는 0으로 나눗셈)을 호출하는 코드는 실행되지 않습니다. 프로그램이 아직 정의되지 않은 동작입니까?
int main(void)
{
int i;
if(0)
{
i = 1/0;
}
return 0;
}
저는 그것이 여전히 정의되지 않은 행동이라고 생각하지만, 기준에서 저를 지지하거나 부인할 증거를 찾을 수 없습니다.
그래, 좋은 생각 있어?
C 표준에서 "동작" 및 "정의되지 않은 동작"이라는 용어를 정의하는 방법을 살펴보겠습니다.
ISO C 2011 표준의 N1570 초안에 대한 언급입니다. 나는 공개된 세 가지 ISO C 표준(1990, 1999, 2011) 중 어느 것에도 관련된 차이를 알지 못합니다.
섹션 3.4:
에 영향을 주다
또는
네, 조금 애매하지만, 저는 주어진 진술은 실제로 실행되지 않는 한 "외모"도 없고, "행동"도 없다고 주장합니다.
섹션 3.4.3:
undefined behavior(되지 않은 동작)
본 부과하지 않는 잘못된 시
그런 구조의 '사용 시'라고 쓰여 있다."사용"이라는 단어는 표준에 의해 정의되지 않기 때문에 우리는 공통적인 영어의 의미로 되돌아간다.구성이 실행되지 않으면 "사용"되지 않습니다.
이 정의에는 다음과 같은 주기가 있습니다.
주 가능한 정의되지 않은 동작은 상황을 완전히 무시하고 예측할 수 없는 결과를 발생시키는 것부터 번역 또는 프로그램 실행 중에 환경 특유의 문서화된 방식으로 동작하는 것(진단 메시지 발행 여부에 관계없이), 번역 또는 실행을 종료하는 것(진단 메시지 발행 시)까지 다양하다.에시지)
따라서 컴파일러의 동작이 정의되지 않은 경우 컴파일 시 프로그램을 거부할 수 있습니다.그러나 이에 대한 저의 해석은 프로그램의 모든 실행이 정의되지 않은 동작에 직면한다는 것을 증명할 수 있어야만 그렇게 할 수 있다는 것입니다.이것은, 제 생각에, 다음과 같은 것을 의미합니다.
if (rand() % 2 == 0) {
i = i / 0;
}
확실히 정의되지 않은 동작을 가질 수 있으며 컴파일 시 거부될 수 없습니다.
실질적으로 프로그램은 정의되지 않은 동작을 호출하는 것을 방지하기 위해 런타임 테스트를 수행할 수 있어야 하며 표준에서는 실행이 허용되어야 합니다.
예를 들어 다음과 같습니다.
if (0) {
i = 1/0;
}
0으로 나눗셈을 실행하지 않습니다.매우 일반적인 관용구는 다음과 같습니다.
int x, y;
/* set values for x and y */
if (y != 0) {
x = x / y;
}
되지 않은 있습니다.y == 0아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아y == 0동작은 잘 정의되어 있습니다.또한 예시와 마찬가지로 정의되어 있지 않은 동작은 실제로 발생할 수 없기 때문입니다.
, (,,INT_MIN < -INT_MAX && x == INT_MIN && y == -1, 넘칠 수 의 문제입니다
코멘트(삭제 후)에서 컴파일러가 컴파일 시 상수 표현을 평가할 수 있다는 지적이 있었습니다.그건 사실이지만, 이 경우엔 관련이 없어요, 왜냐면 이 문맥에서 보면
i = 1/0;
1/0 상수 표현이 아닙니다.
상수 표현식은 조건식으로 축소되는 구문 범주입니다(할당 및 쉼표 표현 제외).생성 상수 표현은 대소문자 라벨 등 실제로 상수 표현이 필요한 컨텍스트에서만 문법에 표시됩니다.다음과 같이 적습니다.
switch (...) {
case 1/0:
...
}
1/0는 상수 표현입니다.또한 6.6p4의 제약조건을 위반하는 표현입니다.각 상수 표현은 그 유형에 대해 나타낼 수 있는 값의 범위에 있는 상수로 평가해야 합니다.따라서 진단이 필요합니다.그러나 할당의 오른쪽에는 상수식이 필요하지 않고 단지 조건식이므로 상수식에 대한 제약은 적용되지 않습니다.컴파일러는 컴파일 시에 할 수 있는 모든 식을 평가할 수 있습니다.다만, 동작은 실행중에 평가된 것과 같은 경우(또는 의 맥락에서)에 한정됩니다.if (0)실행 중에는 평가되지 않습니다.
(상수 표현과 똑같이 보이는 것이 반드시 상수 표현인 것은 아닙니다.x + y * z, " "x + y는 가법 변환이 아닙니다.이는 가법 변환이 표시되는 컨텍스트이기 때문입니다).
즉, N1570 섹션 6.6의 각주를 인용하려고 했습니다.
다음
static int i = 2 || 1 / 0;
1인 입니다.
사실 이 질문과는 관련이 없습니다.
마지막으로 실행 중 발생하는 작업과 관련이 없는 정의되지 않은 동작을 발생시키도록 정의된 몇 가지 사항이 있습니다.C 표준의 부록 J 섹션 2(다시 N1570 초안 참조)는 표준의 나머지 부분으로부터 수집된 정의되지 않은 동작을 일으키는 요소를 나열합니다.예를 들어 다음과 같습니다(전체 목록이라고 주장하지는 않습니다).
- 비어 있지 않은 소스 파일은 백슬래시 문자 바로 앞에 있지 않은 새 행 문자로 끝나지 않거나 부분적인 전처리 토큰 또는 주석으로 끝나지 않습니다.
- 토큰 연결은 범용 문자 이름의 구문과 일치하는 문자 시퀀스를 생성합니다.
- 기본 소스 문자 세트에 포함되지 않은 문자가 토큰으로 변환되지 않는 식별자, 문자 상수, 문자열 리터럴, 헤더 이름, 주석 또는 전처리 토큰을 제외하고 소스 파일에서 발견됩니다.
- 식별자, 주석, 문자열 리터럴, 문자 상수 또는 헤더 이름에 잘못된 멀티바이트 문자가 포함되어 있거나 초기 시프트 상태에서 시작 및 종료되지 않습니다.
- 같은 식별자가 같은 변환 유닛에 내부 링크와 외부 링크를 모두 가지고 있다.
이러한 특정 케이스는 컴파일러가 검출할 수 있는 것입니다.위원회가 모든 구현에 동일한 행동을 강요하고 싶지 않았거나 할 수 없었기 때문에 그들의 행동은 정의되지 않았다고 생각합니다. 그리고 허용되는 행동의 범위를 정의하는 것은 노력할 가치가 없었습니다."실행하지 않는 코드"의 카테고리는 아니지만, 여기서 언급하고 있는 것은 완전함입니다.
이 문서에서는 섹션 2.6에서 다음 질문에 대해 설명합니다.
int main(void){
guard();
5 / 0;
}
은 이 이 '아주 좋다'는 뜻에서 한다.guard()을 사용하다또한 다음과 같이 "정적으로 정의되지 않음"과 "동적으로 정의되지 않음"의 개념을 구분합니다.
표준 뒤에11 있는 의도는 일반적으로 상황에 대한 코드를 생성하기가 쉽지 않은 경우 정적으로 정의되지 않는 것으로 보입니다.코드를 생성할 수 있는 경우에만 동적으로 상황을 정의할 수 있습니다.
11) 위원과의 사적인 서신.
나는 전체 기사를 보는 것을 추천한다.하나로 합치면 일관된 그림이 그려집니다.
기사의 작성자가 위원회 위원과 질문에 대해 논의해야 했다는 사실은 현재 귀하의 질문에 대한 답변에 대한 기준이 모호하다는 것을 확인시켜줍니다.
이 경우 정의되지 않은 동작은 코드를 실행한 결과입니다.따라서 코드가 실행되지 않으면 정의되지 않은 동작이 없습니다.
정의되지 않은 동작이 코드 선언의 결과일 경우(예: 변수 섀도우링의 일부 사례가 정의되지 않은 경우) 실행되지 않은 코드는 정의되지 않은 동작을 호출할 수 있습니다.
이 답변의 마지막 단락으로 하겠습니다.https://stackoverflow.com/a/18384176/694576
...UB는 런타임 문제이지 컴파일 타임 문제가 아닙니다...
즉, UB는 호출되지 않습니다.
표준이 변경되어 코드가 갑자기 "never be executed"되지 않는 경우에만 해당됩니다.하지만 나는 이것이 '정의되지 않은 행동'을 일으킬 수 있는 논리적인 방법을 보지 못한다.아무 것도 유발하지 않아요.
정의되지 않은 행동의 주제에 관해 형식적인 측면과 실제적인 측면을 분리하는 것은 종종 어렵다.이것은 1989년 표준에서 정의되지 않은 동작의 정의입니다(최신 버전은 현재 가지고 있지 않지만 실질적으로 변경되지는 않을 것으로 예상합니다).
1 정의되지 않은 동작휴대할 수 없거나 잘못된 프로그램 구성 또는 사용 시 동작이 국제 표준이 요건을 부과하지 않는 잘못된 데이터2 주 정의되지 않은 가능한 동작은 상황을 완전히 무시하는 것부터 다양하다.번역 또는 프로그램 실행 중에 예기치 않은 결과가 발생함환경 특유의 문서화된 방식으로(그 유무에 관계없이)진단 메시지 발행) 번역 종료 또는실행(진단 메시지 발행 포함)
형식적인 관점에서 보면, 당신의 프로그램은 정의되지 않은 동작을 호출한다고 할 수 있습니다.이것은 표준이 단지 0으로 나눗셈을 포함한다는 이유만으로 실행 시 무엇을 할 것인지에 대한 어떠한 요구도 부과하지 않는다는 것을 의미합니다.
한편, 실용적인 관점에서 보면, 직관적으로 동작하지 않는 컴파일러를 발견하게 되어 매우 놀랐습니다.
기준에는, 제 기억으로는, 규칙이 깨진 순간부터 무엇이든 할 수 있다고 되어 있습니다.어쩌면 글로벌한 풍미를 가진 특별한 이벤트가 있을지도 모릅니다(그런 것에 대해 듣거나 읽은 적은 없습니다).그래서 이렇게 말하죠.아니요, 동작이 올바르게 정의되어 있는 한0은 항상 false이기 때문에 실행 시 규칙을 어길 수 없기 때문에 UB일 수 없습니다.
저는 그것이 여전히 정의되지 않은 행동이라고 생각하지만, 기준에서 저를 지지하거나 부인할 증거를 찾을 수 없습니다.
프로그램이 정의되지 않은 동작을 호출하지 않는다고 생각합니다.
결함 보고서 #109는 유사한 질문에 대처하고 다음과 같이 말합니다.
게다가 특정 프로그램의 가능한 모든 실행이 정의되지 않은 동작을 초래하는 경우, 해당 프로그램은 엄밀하게 준거하고 있지 않습니다.순응 실장은 엄밀하게 순응하는 프로그램을 번역하는 데 실패해서는 안 됩니다.단순히 그 프로그램을 실행할 수 있는 몇 가지 이유가 정의되지 않은 동작을 초래하기 때문입니다.foo는 호출되지 않을 수 있으므로 제시된 예는 적합한 구현에 의해 정상적으로 변환되어야 합니다.
이는 "정의되지 않은 동작"이라는 표현이 어떻게 정의되는지, 그리고 문장의 "정의되지 않은 동작"이 프로그램의 "정의되지 않은 동작"과 동일한지 여부에 따라 달라집니다.
이 프로그램은 C와 비슷하기 때문에 컴파일러에 의해 사용되는 C 표준(일부 답변)에 대한 자세한 분석이 필요합니다.
특정 표준이 없는 경우 정답은 "에 따라 다르다"입니다.일부 언어에서는 첫 번째 오류 후에 컴파일러가 프로그래머가 무엇을 의미하는지 추측하지만 컴파일러의 추측에 따르면 여전히 몇 가지 코드를 생성합니다.다른 순수한 언어에서는 정의되지 않은 것이 프로그램 전체에 전파됩니다.
다른 언어에는 "경계 오류"라는 개념이 있습니다.일부 제한된 유형의 오류에 대해 이러한 언어는 오류가 일으킬 수 있는 손상 정도를 정의합니다.암묵적인 가비지 컬렉션이 있는 특정 언어에서는 오류가 입력 시스템을 무효화하는지 여부가 자주 달라집니다.
언급URL : https://stackoverflow.com/questions/18385020/can-code-that-will-never-be-executed-invoke-undefined-behavior
'programing' 카테고리의 다른 글
| printf()를 사용하여 C의 정수를 인쇄하려면 %i 또는 %d? (0) | 2022.07.11 |
|---|---|
| Vue는 맵 및 세트 데이터 유형에 대한 반응성을 지원합니까? (0) | 2022.07.11 |
| jar 내에서 리소스 파일 읽기 (0) | 2022.07.11 |
| 구성 요소의 vuex 작업에서 상태 데이터를 반환하는 방법 (0) | 2022.07.11 |
| c/c++ 로 로그 베이스(2)를 쓰는 방법 (0) | 2022.07.11 |