a가 초기화되지 않은 경우 a ^ a 또는 aa 정의되지 않은 동작입니까?
이 프로그램을 고려하십시오.
#include <stdio.h>
int main(void)
{
unsigned int a;
printf("%u %u\n", a^a, a-a);
return 0;
}
정의되지 않은 동작입니까?
표면 a
에는 초기화되지 않은 변수가 있습니다. 그래서 그것은 정의되지 않은 행동을 가리 킵니다. 그러나 a^a
와 a-a
동일하다 0
모든 값에 대해 a
, 적어도 나는 그런 경우라고 생각합니다. 행동이 잘 정의되어 있다고 주장 할 수있는 방법이 있습니까?
C11에서 :
a
주소를 사용하지 않으면 6.3.2.1/2에 따라 명시 적으로 정의되지 않습니다 (아래 인용).- 트랩 표현 (액세스시 UB 발생) 일 수 있습니다. 6.2.6.1/5 :
특정 객체 표현은 객체 유형의 값을 나타낼 필요가 없습니다.
부호없는 정수는 트랩 표현을 가질 수 있습니다 (예 : 15 개의 정밀도 비트와 1 개의 패리티 비트가있는 경우 액세스 a
하면 패리티 오류가 발생할 수 있음).
6.2.4 / 6은 초기 값이 불확실 하고 3.19.2 아래의 정의가 지정되지 않은 값 또는 트랩 표현 이라고 말합니다 .
추가 : Pascal Cuoq이 지적한대로 C11 6.3.2.1/2에서 :
lvalue가 레지스터 스토리지 클래스로 선언 할 수있는 자동 저장 기간의 객체를 지정하고 (그 주소를 사용하지 않은 경우) 해당 객체가 초기화되지 않은 경우 (이니셜 라이저로 선언되지 않고 사용 전에 할당이 수행되지 않은 경우) ), 동작이 정의되지 않았습니다.
여기에는 문자 유형에 대한 예외가 없으므로이 절은 이전 논의를 대체하는 것으로 보입니다. 액세스 x
는 트랩 표현이없는 경우에도 즉시 정의되지 않습니다. 이 절 은 실제로 레지스터에 대한 트랩 상태가있는 Itanium CPU를 지원 하기 위해 C11에 추가 되었습니다.
함정 표현이없는 시스템 : 하지만 &x;
6.3.2.1/2의 이의가 더 이상 적용되지 않도록 던져서 함정 표현이없는 것으로 알려진 시스템에 있다면 어떨까요? 그러면 값은 지정되지 않은 값 입니다. 3.19.3에서 지정되지 않은 값 의 정의는 약간 모호하지만 DR 451에 의해 명확 해지며 결론은 다음과 같습니다.
- 설명 된 조건에서 초기화되지 않은 값은 해당 값을 변경하는 것처럼 보일 수 있습니다.
- 불확정 값에 대해 수행되는 모든 작업은 결과적으로 불확정 값을 갖게됩니다.
- 라이브러리 함수는 불확실한 값에 사용될 때 정의되지 않은 동작을 나타냅니다.
- 이 답변은 트랩 표현이없는 모든 유형에 적합합니다.
이 해상도에서 int a; &a; int b = a - a;
결과 b
여전히 불확정 값을 갖는.
불확정 값이 라이브러리 함수에 전달되지 않으면 우리는 여전히 지정되지 않은 동작 (정의되지 않은 동작이 아님)의 영역에 있습니다. 결과는 이상 할 수 있습니다 (예 : if ( j != j ) foo();
foo라고 부를 수 있음 ). 그러나 악마는 비강에 갇혀 있어야합니다.
예, 정의되지 않은 동작입니다.
첫째, 초기화되지 않은 변수는 "깨진"(일명 "트랩") 표현을 가질 수 있습니다. 해당 표현에 액세스하려는 한 번의 시도조차도 정의되지 않은 동작을 트리거합니다. 더욱이 unsigned char
비트 래핑 유형의 객체 (예 :)도 "불확정 값"의 표현으로 나타날 수있는 특수한 플랫폼 종속 상태 (예 : NaT-Not-A-Thing-on Itanium)를 획득 할 수 있습니다.
둘째, 초기화되지 않은 변수는 안정적인 값을 보장 할 수 없습니다 . 동일한 초기화되지 않은 변수에 대한 두 개의 순차 액세스는 완전히 다른 값을 읽을 수 있습니다. 따라서 두 액세스가 a - a
모두 "성공"(트랩이 아님) 이더라도 여전히 a - a
0으로 평가 된다는 보장이 없습니다 .
개체에 자동 저장 기간이 있고 해당 주소를 사용하지 않는 경우 개체를 읽으려고하면 정의되지 않은 동작이 생성됩니다. 그러한 객체의 주소를 취하고 "unsigned char"유형의 포인터를 사용하여 바이트를 읽는 것은 "unsigned char"유형의 값을 산출하는 것이 표준에 의해 보장되지만 모든 컴파일러가 이와 관련하여 표준을 준수하는 것은 아닙니다. . 예를 들어 ARM GCC 5.1은 다음과 같습니다.
#include <stdint.h>
#include <string.h>
struct q { uint16_t x,y; };
volatile uint16_t zz;
int32_t foo(uint32_t x, uint32_t y)
{
struct q temp1,temp2;
temp1.x = 3;
if (y & 1)
temp1.y = zz;
memmove(&temp2,&temp1,sizeof temp1);
return temp2.y;
}
will generate code that will return x if y is zero, even if x is outside the range 0-65535. The Standard makes clear that unsigned character reads of Indeterminate Value are guaranteed to yield a value within the range of unsigned char
, and the behavior of memmove
is defined as equivalent to a sequence of character reads and writes. Thus, temp2 should have a value that could be stored into it via sequence of character writes, but gcc is deciding to replace the memmove with an assignment and ignore the fact that code took the address of temp1 and temp2.
Having a means of forcing a compiler to regard a variable as holding a arbitrary value of its type, in cases where any such value would be equally acceptable, would be helpful, but the Standard doesn't specify a clean means of doing so (save for storing some particular value which would work, but often be needlessly slow). Even operations which should logically force a variable to hold a value that would be representable as some combination of bits cannot be relied upon to work on all compilers. Consequently, nothing useful can be guaranteed about such variables.
'programing tip' 카테고리의 다른 글
일반 배열에 대한 범위 기반은 어떻게 작동합니까? (0) | 2020.10.22 |
---|---|
왜 이것을 람다에서 참조 ( '& this')로 캡처 할 수 없습니까? (0) | 2020.10.22 |
Convert.ToBoolean (string)과 Boolean.Parse (string)의 차이점은 무엇입니까? (0) | 2020.10.22 |
열의 공통 값을 기반으로 큰 데이터 프레임을 데이터 프레임 목록으로 분할 (0) | 2020.10.22 |
Windows 용 GitHub가 GitLab에서 작동하나요? (0) | 2020.10.22 |