말도 안되는 질문.. 혹시 트릭있나요? [문자열을 변수명으로 변
글쓴이: neohwang / 작성시간: 금, 2003/10/17 - 3:48오후
#include <stdio.h> int main(int argc, char *argv[]) { char *var[2]={"aaa","bbb"}; int aaa=10; int bbb=20; printf("%d",var[0]); <--- 목적은 printf("%d",aaa); 를 하고 싶은 것 입니다. return 0; }
당연히 위 코드는 문제가 있습니다.
저의 목적은 var[]로 선언된 값을 가지고, 그 값 자체를 다른 곳에서 선언된 변수명과 같을 경우 var[]에 선언된 값으로 그것을 대체해야만 하는 상황입니다.
복잡하죠?
근데 이게 C에서는 허용이 안되죠?
혹시 트릭이 있나요?
저게 허용안되면,
소스 길이가 무진장 길어지거든요....
사실은 var[]의 길이가 200개 정도 되는거거든요.
그리고 int aaa=10; 처럼 된 것은 구조체 속에 있는 것이고,, 그 구조체 내용을 바꿀수 없는 상황인지라...
즉, 한 번 200개 문자열을 배열로 선언하고, 그 문자열을 출력하고, 구초제에서 같은 문자열의 값을 빼와서 출력하고... 뭐 이런식으로 하고 싶은데요.
고수님들... 트릭없나요?
Forums:
associative array를 사용해야겠네요. C++의 map 같은.
associative array를 사용해야겠네요. C++의 map 같은.
Re: 말도 안되는 질문.. 혹시 트릭있나요? [문자열을 변수명으로
우선 다음이 맞는가요? 그리 어렵지 않게 구현할 수 있을 듯 싶은데.
1.저 var 의 문자열들은 구조체 내의 멤버 이름이라는 것을 의미하신 건가요?
그러니까, 하나의 구조체 멤버가 200여개 정도 된다는 것인지요?
2. 1이 맞다면 그 멤버들의 타입도 변할 수 있죠?
Orion Project : http://orionids.org
1번 맞습니다.근데.. 2번에서 type이 바뀔수 있다는 말씀은.
1번 맞습니다.
근데.. 2번에서 type이 바뀔수 있다는 말씀은.... 잘 모르겠거든요.
뭐 대충 이렇게 하고 싶은 것 입니다.
혹시 #define 문 같은 걸로도 안되죠?
지금은 멤버들이 전부 int 인데, 혹시 다른 타입도 사용됐는지에대한
지금은 멤버들이 전부 int 인데, 혹시 다른 타입도 사용됐는지에
대한 것이었구요.
지금처럼 처리 대상인 모든 멤버들의 타입이 같고, 그들이 연속으로
붙어 있다면,
저 p 를 0~199 까지 유효하게 쓸 수 있는 int* 로 가정해도 됩니다.
그러면 문자열 인덱스와 동일하게 일치시킬 수 있죠.
좀 더 일반적이고 타입이 변하는 경우도 처리하려면,
;'멤버이름, 오프셋, 타입 코드' 테이블을 만드는 겁니다.
예를 들어,
저 name 문자열이 소트돼 있으면 bsearch 를 쓸 수도 있고, 여의치
않으면 선형 탐색해도 되구요. offset 으로 포인터를 얻은 뒤, 타입
코드에 따라, 캐스트해서 값을 쓰는 거죠.
다음 매크로를 쓰면 table 초기화가 더 쉬워지겠죠.
#define TABLE_ENTRY(name,type) { #name, offsetof(struct info,name), type }
Orion Project : http://orionids.org
스승님~~~~ ^^언제 체스 한 판 두시죠.
스승님~~~~ ^^
언제 체스 한 판 두시죠.
[quote="체스맨"]지금은 멤버들이 전부 int 인데, 혹시 다른 타
(int 이기에 가능성이 적기는 하지만) 완벽한 이식성은 없습니다. 추가적인
padding 에 의해,
가 참일 수 있습니다.
유일하게 안전한 방법입니다 - 이를 위해 offsetof 가 제공되고 있습니다.
--
Jun, Woong (woong at gmail.com)
http://www.woong.org
혹시 도움이 될까 해서 간단한 소스를 만들었습니다.반드시 문자열배열일
혹시 도움이 될까 해서 간단한 소스를 만들었습니다.
반드시 문자열배열일 필요는 없을거 같아서
enum 형을 사용해보시는 것도..생각해보세요
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef enum{aaa,bbb} mytype;
struct que
{
int aaa;
int bbb;
};
#define var(obj, member) obj.member
#define prn(member) printf("(%d)\n",q.member)
int main()
{
struct que q;
q.aaa= 10;
printf("(%d)\n", var(q,aaa));
q.aaa = 20;
prn(aaa);
return 0;
}
사실 표준에 의거해서 첫번째 방법이 이식성이 없을 것이라는 답변을예상
사실 표준에 의거해서 첫번째 방법이 이식성이 없을 것이라는 답변을
예상 했었습니다. 8)
int 이기에 가능성이 적다고 보기는 어렵습니다. 애초에 "표준에 의거하여
완벽한 이식성이 있는 방법이 아니기에"라면 모르죠.
하지만, 실질적으로 위와 같은 방법이 이식성을 보장하지 못하는 경우는
없다고 보아도 됩니다.
offsetof(struct _a,a)==offsetof(struct _b,a0)
추가적 패딩이 일어나더라도, 그것은 _a::a[0] 또는 _b::a0 이전에서
일어납니다. &a[0] (또는 &a0 ) 를 sizeof(int) 의 배수 주소에 위치하도록
만듭니다.
이후 동일한 타입이 연속되는 한 그 사이에 패딩은 일어날 이유가 없으므로,
실질적인 시스템에서 그렇게 하지 않을 것입니다.
물론 위 방법이 항상 적합하다는 것을 표준이 보장하지는 않는다는 것에는
동의합니다.
* 만일, 시스템 또는 컴파일러의 기본 구조체 정렬을 무시하고,
강제로 pack 이나, 지정된 길이로 정렬시킨다면 문제가 발생할 수도
있습니다. 특히 "최대 정렬 길이"<sizeof(_type) 라면
(예를 들어 위 예에서 _type은 int ) int* 로 간주하는 경우, 특정
시스템에서 bus error 가 일어날 수도 있죠.
강제로 정렬 규칙을 바꾸지 않는 경우라면 실질적으로는 문제가 발생할
가능성은 없다고 볼 수 있습니다.
* 그리고 또 하나,
만일 위와 같이 구조체 정렬을 억지로 바꿔버린 경우라면, 제가 제시한
두번째 예제도 문제를 일으킬 수 있습니다. 예를 들어
표준에 의거한 이식성을 극한으로 보장받고 싶다면, switch 가
적합하겠죠.
이식성 고려하다보면 한도 끝도 없을 때가 있는 것 같습니다...
Orion Project : http://orionids.org
어렵게 하시네요..무슨작업인지 모르겠지만 #!/usr/bi
어렵게 하시네요..
무슨작업인지 모르겠지만
#!/usr/bin/perl -w
@array=(var1, var2, var3, var4 ...);
for (0..$#array)
{
${$array[$_]} = {value.$_};
}
ㅋㅋㅋ.. 쉽죠..
아마도 텍스트 처리하시는게 아닐까 싶으네요..
[quote="체스맨"]사실 표준에 의거해서 첫번째 방법이 이식성이 없을
네, 저도 알고 계시면서 int 형이고 동일한 type 의 연속이기에 그런 사실
을 언급하셨을 것이라 예상했습니다. :-)
"int 이기에 가능성이 적기는 하지만" 부분을 오해하고 계신 것 같습니다.
가장 자연스러운 크기를 갖는 (그래서 일반적으로 word size 인) int 형이
기에 실제 문제를 일으킬 가능성이 적다는 뜻이었습니다. 즉, 표준 차원에
서의 엄격한 이식성은 없지만, 실제 문제를 일으킬 경우는 "현재로서는" 많
지 않다는 뜻이었습니다.
물론, 이 역시 다소 엄격한 이식성에서 나오는 해석입니다만
offsetof(struct _a,a)==offsetof(struct _b,a0)
도 보장되지는 않습니다. 동일한 구조체 layout 은 "가장 엄격하게는"
- 호환되는 구조체형 혹은 같은 initial sequence 를 갖는 공용체의 멤버인
구조체에서만 보장됩니다.
또 보다 더 현실적으로는, 동일한 layout 은
- 호환되는 구조체 멤버열에서 보장됩니다.
int a[3]; 와 int a0; 는 호환되는 type 의 구조체 멤버가 아닙니다 - 물론
그 이전에 struct _a 와 struct _b 가 호환되는 구조체형이 아니기에 첫번
째 멤버 앞에 padding 이 없다는 사실만을 제외하면 나머지는 padding 은
(나머지 규칙을 만족한다는 조건 아래) 임의적일 수 있습니다.
따라서, 이식성에 대한 이야기라면 a[1] 와 a1 의 관계를 떠나 a[0] 과 a0
의 관계조차 보장되지 않습니다. 물론, 위에서 처음 보여주신 예에서는 a[]
와 a0 가 구조체의 첫번째 멤버였기에 최소한 a[0] 과 a0 의 관계는 보장됩
니다.
설사
offsetof(struct _a,a)==offsetof(struct _b,a0)
를 보장받는다고 해도, a 와 a0 의 type 이 각각 array of char 와 char 인
경우에는 문제가 달라질 수 있습니다 - 달라진 적이 있습니다. 오래 전에
쓰인 Prime C compiler 는
에서 a[] 는 연속된 3개의 바이트에, 반면 a0, a1, a2 사이에는 1 바이트의
padding 을 넣어서 정렬합니다 - 따라서, a[1] 과 a1 의 offset 이 다릅니
다. 그리고, Prime-serise 는 (비록 구식이지만) "실질적인" 시스템이었습
니다. 물론, 오래 전에 쓰인 한 컴파일러에서 보장되지 않는 사실이라는 이
유만으로 써서는 안 된다고 주장하는 것은 아닙니다. 다만, "동일한 type
이 연속되는 경우 실질적인 시스템에서 padding 이 있을 이유가 없다" 는
명제가 일반적 참이 될 수 없음을 말씀드린 것 뿐입니다.
그리고 거의 모든 경우에 (보통 정렬 제한에 꼭 맞는) int 형이 연속적으로
주어진 경우이기에 제가 말씀드리고 있는 문제가 일어날 가능성이 거의 없
다고 생각하지만, 64-bit machine 의 경우 word 가 64 bits 이지만 프로그
래머의 편의와 backward compatibility 를 위해 int 형을 32 bits 로 (대신
long int 부터 64 bits 로) 제공하는 경우에도 다른 결과가 나올 수 있다고
생각할 수 있습니다.
반대로 멤버 간에 넉넉한 padding 을 제공하는 경우에는 기본적인 정렬 제
한 문제를 일으키지 않으면서도 말씀하신 무관한 두 구조체 멤버 사이의 관
계를 보장받지 못할 수 있습니다. 구조체 padding 이 반드시 최소화되어야
한다는 요구는 없습니다.
아무 문제 없습니다. 아마도 implementation 이 구조체 멤버 정렬을 임의로
강제해 pointer to int 가 제대로 정렬되지 않은 int 형 멤버에 접근하는
것에 대한 문제를 말씀하고 계신 것 같습니다. 하지만, 위의 문맥에서
*b = 1;
가 성공한다는 사실을 표준이 보장합니다. 따라서, 이에 문제를 일으키는
implementation 은 (어차피 표준을 지키지 않으므로) 이식성과 관련된 논의
에서 제외됩니다. 그리고, 말씀드렸듯이
- (위에서 보인 Prime 이나 64 bit machine 의 특수한 경우처럼) 넉넉한
padding 을 사용하거나
- 단일 byte 로의 접근이 (비효율적이라도) 항상 가능한
상황에서는 *b 로의 대입이 항상 성공하면서 다른 구조체 멤버 간의 관계는
보장되지 않을 수 있습니다 - 혹은 않아도 됩니다.
제가 이 글을 통해서 상당수의 implementation 에서 이미 참인 (따라서, 큰
걱정없이 의존해 쓸 수 있고, 다수의 implementation 이 그러한 기대를 만
족시켜주는) 기술을 이론적 이식성이 없다는 이유만으로 "모든" 경우에 사
용해서는 안 된다고 주장하는 것은 아닙니다. 다만, offsetof 를 사용해
table-driven 방법을 사용하면 이식성에 전혀 손상 없이 원하는 결과를 얻
을 수 있는 경우, 굳이 이식성이 없는 방법으로 갈 필요는 없다는 것이 제
글의 요입니다. 보여주신 offsetof 를 통한 table-driven programming 은
지극히 일반적인 프로그래밍 방법입니다. 말씀드렸듯이 그와 같은 프로그램
구조를 지원하기 위해 offsetof 매크로가 추가되었고 그 결과를 정수 상수
로 규정하고 있습니다 - C99 에서는 달라졌지만 이전에는 aggregate type
의 초기치에는 반드시 상수 수식만이 허락되었습니다. 실제 제가
<locale.h> 이나 text parser 구현하는 경우에도 이식성과 유지 보수를 위
해 offsetof 를 통한 table-driven 방법을 사용했으며 (offsetof 와는 무관
하지만 FSM 구현에도 table-driven 방법을 선호합니다), 이렇게 offsetof
를 사용해 struct 내부로 접근하기 위한 table 을 구성하는 경우에는 어렵
지 않게 까다로운 이식성을 보장받을 수 있습니다.
그럼...
--
Jun, Woong (woong at gmail.com)
http://www.woong.org
이식성 논의는 충분히 된 것 같구요.개발자의 의도로 이식성의 수준이
이식성 논의는 충분히 된 것 같구요.
개발자의 의도로 이식성의 수준이 결정되리라 봅니다.
제가 제시한 첫번째 방법은 대부분의 경우 문제가 없을 것이고,
제대로 개발이 되는 경우라면, 애초에 제가 제시한 첫번째 방법이 나오지
않도록, 상황에 따라 필요한 경우 배열을 사용하거나, 다른 자료구조를
검토했을 것입니다.
질문하신 분의 상황에 맞추어 보면, 첫번째 방법은 좋은 방법 중 하나입니다.
소스 코드가 격감될 수 있고, 대부분의 상용 시스템에서 잘 작동하는 트릭이지요.
하지만,
이것은 인정하기 어렵습니다. 다음 내용은 정렬되지 않은 주소를
사용하는 경우 bus error 가 존재하는 머쉰이라는 것을 가정합니다.
이 상황에서 컴파일러는 b 가 정렬되지 않은 주소인 것을 체크하는
코드를 넣지 않고, atomic operation 코드를 생성할 것입니다.
하지만,
(int*)&a[1] 이 pack 된 struct _a 에서 &a.b와 같습니다. 이것은
bus error 가 납니다. 이것은 struct _a* 를 받아서 pa->b = 1;
로 해야만 컴파일러가 제대로 처리할 수 있는 문제입니다.
그래서, 이것까지 고려한다면 memcpy 를 쓰는 방법이 있지만,
특정 타입의 포인터, 예를 들어, int* 를 인자로 갖는 함수에 대해
항상 그런 식으로 할 수는 없는 일이죠.
Orion Project : http://orionids.org
[quote="체스맨"]이식성 논의는 충분히 된 것 같구요.개발자의
처음 의도가 이렇게 이식성 이야기를 거창하게 끌고 가는 것은 아니었습니
다. 다만, "잘 작동하는 트릭" 과 "항상 작동이 보장되는 방법" 사이의 구
분을 말씀하지 않으셔서 그에 대한 구분을 언급하려는 의도일 뿐이었습니다.
표준이 작동을 보장한다는 사실은, 만약 그와 같이 무절제한 구조체
packing 이 bus error 로 인해 그 대입문을 오작동하게 만들 수 있다면
packing 을 해서는 안 된다는 것을 의미합니다.
즉, 표준이 보장하기에 bus error 가 있고 무리한 packing 이 있어도 잘 작
동한다고 주장하는 것이 아니라, 표준이 보장하기에 bus error 가 있는
implementation 은 그와 같은 무리한 packing 을 해서는 안 된다는 것을
말씀드린 것입니다.
그리고, 그런 가능성을 생각해, 문제가 되었던 구조체 멤버 사이의 관계는
반드시 구조체 packing 에 의해서만 깨질 수 있는 것이 아니라, 반대로 넉
넉한 padding 을 넣음으로써도 깨질 수 있다는 사실을 말씀드린 것입니다.
--
Jun, Woong (woong at gmail.com)
http://www.woong.org
[quote="전웅"]아마도 implementation 이 구조체 멤버
위 문장으로 부터, 말씀하신 것처럼 "*b=1 을 표준이 보장하기 때문에,
pack 옵션을 사용해서는 안된다"는 뜻으로 이해하기는 어려웠기 때문에,
( pack 옵션을 사용해도 *b=1 이 보장된다로 이해가 됐었습니다. :) )
pack 옵션을 주는 경우 bus error 가 유발될 수 있고,
int* b = &a->b 트릭도 간단히 오류가 유발될 수 있다는 것을 말씀드렸구요.
* 혹시나 해서, 회사에 있는 먼지쌓인 sparc 머쉰을 켜서 테스트까지
해봤습니다. 8)
결론적으로 저 트릭이 구조체 정렬을 임의로 변경하지 않는한 크게 문제를
일으키지 않으므로, 처음 질문하신 분의 상황 ( 소스를 고칠 수 없고, 구현이
작아졌으면 좋겠고 - 그런 상황이라면 그다지 극심하게 포팅해야 할 상황도
없으리라 예상되는 )에서는 충분히 사용 가능한 방법이라는 점에서 언급을
했던 것입니다.
어떤 방법이 문제를 일으키지 않는 가장 일반적인 방법인가에 대해서
제대로 강조되지 못한 점은 있는 것 같군요.
사족으로 아무튼, __attribute__((packed)) 를 사용하는 것은 좋지 않은
습관인 것은 확실합니다. 회사에서 vc 프로젝트 옵션을 1바이트 정렬로
통일해서 쓰더군요. 항상,
"윈도우즈, 인텔 x86 뿐이다."
이런 거죠. -_-
인텔의 새로운 프로세서들이 정렬되지 않는 주소에 대해 bus error를
유발할 지 모르겠네요. 그러면 위와 같은 이유로 지금 개발하는 소스에서
죽는 부분도 분명 생겨날 가능성이 있겠죠.
Orion Project : http://orionids.org
[quote="체스맨"]어떤 방법이 문제를 일으키지 않는 가장 일반적인
예, 이것이 제가 처음 int [] 로의 접근에 대해 언급했던 이유입니다. 너무
나 매력적이기에 부주의하게 일반화될 가능성이 큰 트릭이기 때문이지요.
넵, 특정 구조체의 layout 에 의존하는 프로그램은 지극히 바람직하지 않습
니다 - 물론, 이기종간 data transfer 의 가능성이 있는 경우에는 멤버를
손수 pack 하는 overhead 를 피하기 위해 의도적으로 의존하는 경우도 있습
니다만...
만약, 구조체 layout 이 성능의 손해를 감수하면서까지 거의 모든 프로그램
에서 의존할 가치가 있는 것이었다면, 표준 차원에서 뭔가 조치가 이루어졌
을 것입니다.
--
Jun, Woong (woong at gmail.com)
http://www.woong.org
에구구.... 질문자인데요.대단하신 두 분께 많이 배웁니다. 고맙
에구구.... 질문자인데요.
대단하신 두 분께 많이 배웁니다. 고맙습니다. ^^
댓글 달기