C언어 포인터변수에 임의의 주소값을 넣어도 되나요?

tmal의 이미지

포인터 변수에 주소값을 넣는 것에 대해서 궁금한 것이 생겨서 질문올립니다.

코드1

int a;
 
int*ptr = &a+20;
int*ptr2 = &a-20;
 
*ptr = 10;
*ptr2 = 20;
 
printf("%d\n",*ptr);
printf("%d\n", *ptr2);
이렇게 했더니, 값이 정상적으로 나왔습니다.그런데, &a의 주소값을 포인터 변수에 담은 것도 아니고, &a+20과 &a-20을 포인터 변수에 담았는데, 어떻게 정상적으로 작동하는걸까요? 이것이 되길래 한가지 더 실험을 해보았습니다.

코드2

int *ptr=(int*)(0x001EFC18);
 
*ptr = 22;
 
printf("%d\n",*ptr);
그런데, 코드1과는 다르게 코드2는 오류가 뜨더군요. 두 코드 다 변수의 주소값을 그냥 넣은 것이 아닌데, 왜 한쪽만 오류가 뜨는 건가요? 궁금합니다.

라스코니의 이미지

int a;
 
int*ptr = &a+20;
int*ptr2 = &a-20;

와 같은 코드는 비록 스터디 목적이라고 할지라도 화들짝 놀라게 되는 코드네요.

일단 위의 코드가 어떻게 실행이 되는지에 대해서는 둘째치고, 이제 ptr은 &a가 되었던 &a+20이 되었던 컴파일러/OS가 허용하는 유효한 readable/writable 주소값을 가지게 되었으므로 값을 저장할수도 있고 읽을수도 있는 것이죠.

int *ptr=(int*)(0x001EFC18);

의 경우는 0x001EFC18 가 OS/하드웨어에서 허용하는 주소가 아니므로 동작하지 않는 것입니다.

int a;
 
int*ptr = &a+20;
int*ptr2 = &a-20;

와 같은 경우 int*ptr = &a+20; 실행문의 결과로 ptr은 stack 공간으 한 부분을 가리키게 되기 때문에 소프트웨어 crash, 심지어 시스템 hacking 으로도 사용될 수 있습니다.
tmal의 이미지

그렇다면, 자료형 (int*)으로 바꿔주는 것은 스택 메모리를 가리키는 주소값(숫자)가 아니라는 말인가요?.
포인터 자료형이 도대체 무엇을 의미하는지 궁금합니다. 자료형이 포인터이면, 스택 세그먼트의 주소값을 나타내는 숫자가 되는 게 아니라는 말씀이신가요?

라스코니의 이미지

(int *)0xABCDABCD 라는 것은 그것이 int 형의 주소값이 라는 것을 상징합니다.
하지만 그 주소값이 유효한지에 대해서는 관여하지 않죠. 어떤 embedded system에서는 유효할 지 모르지만 linux 특히나 64 bit OS에서는 유효하지 않습니다. 이 시스템에서 주소값은 역시 64 bit 사이즈를 가지게 되기 때문이죠.

스택 주소를 가지고 어떻게 하고 싶으시면
int a;
int*ptr = &a+20;
가 맞습니다.
printf("stack addr %p\n", &a);
해보시면 그 주소를 알수가 있습니다.

tmal의 이미지

그런데 주소값이 유효하지 않다는게 무슨 뜻인가요? 혹시, &a는 (int*)(0xABCDABCD)과는 다른 의미를 가지고 있는 것인가요? 어떤 변수의 주소값과 포인터로 형변환시킨 어떤 상수와는 어떤 차이가 있는건가요?

라스코니의 이미지

printf("stack addr %p\n", &a);
를 한번 실행해 보세요. 0xABCDABCD가 가르키는 메모리 주소에 저장하고 거기로부터 읽어오는 것이기 때문에 OS에서 허가해준 메모리 영역이어야 하죠. 임의의 값이 아니라.

익명 사용자의 이미지

포인터 변수라는게 주소값을 저장하는 변수라고 알고 있습니다. 그래서 임의의 주소값을 넣는게 가능합니다. 임의의 값을 넣었을 경우 에러가 날 수도 있고 안 날 수도 있습니다. 그래서 항상 주의를 해야하는게 포인터입니다.

int a; 는 int 형 숫자를 저장할 수 있는 변수 a 입니다. int 형의 숫자 범위는 시스템마다 다를 수 있습니다. max int, min int 이런 상수가 있을 겁니다. 매번 까먹으니.. ㅎㅎ

int *a; 는 포인터입니다. 주소값을 저장하는 변수입니다.
int b = 100; 이라고 하면 b 라는 변수에 100 이 들어가 있고,
&b 는 주소값을 의미합니다. 그래서 a = &b 이렇게 사용합니다.
*a 는 a 주소에 저장된 값을 의미합니다. *a 는 b 에 저장된 값을 가리킬 겁니다.

printf ("%p\n", a); 이렇게 하면 a 가 가리키는 주소값이 출력됩니다.
a 에 주소값이 저장되어 있는 것이죠.

printf ("%d\n", *a); 이렇게 하면 *a 의 값이 출력되는데 a 가 b 주소를 가리키므로 b 에 저장된 100 이 출력될 것으로 보입니다.

틀린게 있으면 지적해 주시기 바랍니다.

포인터가 잘 이해되지 않는다면 시중에 C 포인터 예제만 다루는 책이 있을 겁니다.
그런 책 한 권 보시면 이해가 될 것으로 생각합니다. 그래도 이해되지 않으면 컴퓨터구조 책을 보셔야 합니다.

*a, a, b, &b 의 표현에 대한 일관성 이런 건 생각하지 마십시오.
C 표현에 C++ 표현과 왜 다를까.. 이런 거 생각하면 안 됩니다.
표현은 그냥 외우는 겁니다. 외국어 공부할 때 일관성 따지면 공부 못 합니다. 관용 표현, 속담, 숙어가 있듯이 표현은 그냥 외우는 겁니다.

건투를 빕니다.

jick의 이미지

C를 처음 배우는 사람들이 흔히 하는 실수인데, C/C++은 절대 친절한 언어가 아닙니다.

그래서 "잘못된 코드를 썼을 때 잘못된 동작을 하는" 것을 절대 보장하지 않습니다. 유일하게 보장을 하는 건 "올바른 코드를 썼을 때 올바른 동작을" 하는 것일 뿐입니다.

그러니까 "어 이 코드는 잘못된 코드인 것 같은데 왜 제대로 동작(??)하나요?" 같은 질문은 큰 의미가 없습니다. 그런 코드는 C 컴파일러와 시스템 버전과 옵션과 그날의 기분에 따라 동작을 할 수도 있고 안할 수도 있고 뭐든지 할 수 있습니다. 그냥 그런 코드를 쓰면 안된다고 이해하면 됩니다.

* 뭐, 달리 보면 "자 그럼 이 코드가 실제로 어셈블리로 무슨 코드로 바뀌는지 봅시다" 해서 들여다보는 것도 컴파일러와 컴퓨터 구조를 이해할 수 있는 방법이긴 한데 그런 측면은 다른 분들이 이미 설명해 주신 것 같고...

tmal의 이미지

C를 어느 정도 배웠다 싶으면, 컴퓨터 구조를 공부할려고 하는데요. 컴퓨터 구조를 배우는 데에 어셈블리를 공부하는 것이 좋을 까요? 아님 따로 컴퓨터 구조 책을 사서 읽는 것이 나을 까요? 어셈블리를 (취미로) 한번쯤은 배워보고 싶긴 한데, 주변에서 어셈블리를 공부할 바에는 차라리 그 시간에 다른 걸 공부하는 게 낫다고 해서 어떻게 하는 것이 좋을까요?

익명 사용자의 이미지

컴퓨터 구조를 공부할 때는 자연히 어셈블리어를 배우게 됩니다. 사실 좀 더 엄밀히는 기계어를 배우게 되죠.

문자 그대로 컴퓨터의 언어니까요.

물론 현대 소프트웨어 공학에서 어셈블리어를 쓸 일은 거의 없긴 합니다만, 그렇다고 어셈블리어가 전혀 공부할 필요가 없는 언어인 것은 아니지요.

사용처가 매우 좁은 것일 뿐, 어셈블리어를 배우고 사용해야 하는 분야에서 어셈블리어의 위상은 여전합니다.

tmal의 이미지

그렇다면, 만약 배운다면, 어떤 어셈블리를 배우는 것이 좋을까요? nasm이나 masm등등.. 종류가 많더군요.
kldp에서 어셈블리를 찾아보던 중에, 예전에 이재범이라는 분이 한글로 번역하신 pcasm. pdf를 발견했는데요. 그래서 나중에 어셈블리를 배운다면, nasm으로 한번 배워볼까 생각중입니다.

제가 윈도우7 64bit 운영체제를 사용하는데요. nasm 어셈블러가 리눅스에서만 돌아가나요?
그리고, 어셈블리를 처음 배울때, nasm부터 시작해도 괜찮을까요?

익명 사용자의 이미지

아무래도 상관 없습니다. C언어 처음 배우는 사람한테 gcc가 좋은지 llvm/clang이 좋은지 묻는 격이죠

분명 차이가 있기는 합니다만 초보자일 땐 그 차이가 그렇게 중요하지 않고, 어느 정도 실력과 경험이 붙게 되면 다른 툴로 넘어가는 데 들어가는 노력이 그다지 크지 않아요.

http://kipirvine.com/asm/

저는 이 분의 책으로 어셈블리어를 처음 배웠습니다. 이젠 8판까지 나왔네요. 번역도 꾸준히 되고 있는데, 몇 판까지 번역되어 나왔는지는 잘 모르겠습니다.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.