2015-01-28 3 views
5

unsigned long longunsigned int 값이 할당되었을 때 장면 뒤에서 무슨 일이 일어나고 있는지보고 싶었습니다. 나는 그것을 밖으로 시도하는 간단한 C++ 프로그램을 만들어) (주에서 모든 IO 이동 : 그것을 만드는 ++은 C에서부호없는 int를 부호없는 long long에 잘 정의 했습니까?

0000000000400950 <main>: 
    400950:  55      push %rbp 
    400951:  48 89 e5    mov %rsp,%rbp 
    400954:  48 83 ec 20    sub $0x20,%rsp 
    400958:  89 7d ec    mov %edi,-0x14(%rbp) 
    40095b:  48 89 75 e0    mov %rsi,-0x20(%rbp) 
    40095f:  83 7d ec 02    cmpl $0x2,-0x14(%rbp) 
    400963:  74 05     je  40096a <main+0x1a> 
    400965:  e8 3a ff ff ff   callq 4008a4 <_Z5usagev> 
    40096a:  48 8b 45 e0    mov -0x20(%rbp),%rax 
    40096e:  48 83 c0 08    add $0x8,%rax 
    400972:  48 8b 00    mov (%rax),%rax 
    400975:  48 89 c7    mov %rax,%rdi 
    400978:  e8 0b fe ff ff   callq 400788 <[email protected]> 
    40097d:  89 45 f0    mov %eax,-0x10(%rbp) 
    400980:  83 7d f0 00    cmpl $0x0,-0x10(%rbp) 
    400984:  79 0a     jns 400990 <main+0x40> 
    400986:  8b 45 f0    mov -0x10(%rbp),%eax 
    400989:  89 c7     mov %eax,%edi 
    40098b:  e8 31 ff ff ff   callq 4008c1 <_Z11atoiWarningi> 
    400990:  8b 45 f0    mov -0x10(%rbp),%eax 
    400993:  89 45 f4    mov %eax,-0xc(%rbp) 
    400996:  48 c7 45 f8 ff ff ff movq $0xffffffffffffffff,-0x8(%rbp) 
    40099d:  ff 
    40099e:  8b 45 f4    mov -0xc(%rbp),%eax 
    4009a1:  48 89 45 f8    mov %rax,-0x8(%rbp) 
    4009a5:  48 8b 45 f8    mov -0x8(%rbp),%rax 
    4009a9:  48 89 c7    mov %rax,%rdi 
    4009ac:  e8 66 ff ff ff   callq 400917 <_Z6resulty> 
    4009b1:  b8 00 00 00 00   mov $0x0,%eax 
    4009b6:  c9      leaveq 
    4009b7:  c3      retq 

-1 :

#include <iostream> 
#include <stdlib.h> 

void usage() { 
     std::cout << "Usage: ./u_to_ull <unsigned int>\n"; 
     exit(0); 
} 

void atoiWarning(int foo) { 
     std::cout << "WARNING: atoi() returned " << foo << " and (unsigned int)foo is " << 
((unsigned int)foo) << "\n"; 
} 

void result(unsigned long long baz) { 
     std::cout << "Result as unsigned long long is " << baz << "\n"; 
} 

int main(int argc, char** argv) { 
     if (argc != 2) usage(); 

     int foo = atoi(argv[1]); 
     if (foo < 0) atoiWarning(foo); 

     // Signed to unsigned 
     unsigned int bar = foo; 

     // Conversion 
     unsigned long long baz = -1; 
     baz = bar; 

     result(baz); 

     return 0; 
} 

이 결과 어셈블리가 메인이 생산 -0x8(%rbp)baz ($0xffffffffffffffff으로 인해)에 해당 함을 분명히하십시오. -0x8(%rbp)%rax에 의해 기록되어 있지만, %rax의 상위 4 바이트, %eax이이 -0x8(%rbp)의 상위 4 바이트가 정의되지 않은 것을 제안 하는가

을 할당 할당 된하지 나타납니다? Intel® 64 and IA-32 Architectures Software Developer Manuals에서

+0

64 비트 레지스터의 상단 절반은 하단 절반에만 쓸 때 0이됩니다. – harold

+0

@harold, 명시 적으로 'cltq'가 필요하다고 생각 했습니까? – asimes

+0

결과 함수의 출력은 무엇입니까? – abcthomas

답변

5

, 볼륨 1, 챕터 3.4.1.1 (64 비트 모드에서 범용 레지스터)는, 그

32 비트 피연산자 32 비트 결과를 생성에 제로 - 확장 말한다 목적지 범용 레지스터의 64 비트 결과

그래서 mov -0xc(%rbp),%eax 후, rax 의 상반부는 정의이며, 그것은 제로입니다.

이것도 xchg eax, eax87 C0의 부호화에 적용되지만,하지 (위에 인용 규칙 위압, nop로 정의된다)의 90 인코딩.

+0

대단히 감사합니다. 내가 놓친 것이나 미친 가치가 결국에는 나타나기 시작했다. – asimes

3

C++ 98 (및 C++ (11)이 변경되지 않은 것 같다) 4.7/2에서 (통합 변환 - 어떤 프로모션 관련이 없습니다) 우리가 배울 : 대상 유형은 서명되지

경우, 결과 값은 최소 이며 소스 정수 (2n의 모듈러 인 경우 n은 이고 부호없는 유형을 나타내는 데 사용되는 비트 수)와 일치하는 부호없는 정수입니다.

이것은 소스와 대상이 부호가없고 대상이 원본보다 크지 만 값이 변경되지 않는다는 것을 분명히 보여줍니다. 컴파일러가 큰 값을 동일하게 만드는 데 실패한 코드를 생성하면 컴파일러가 버그가 발생합니다.