C는 문자 처리에 좋은 언어이다??

ratmhun의 이미지

ABookonC 8장 연습문제 9번입니다.

Quote:

C는 문자 처리를 위해 좋은 언어라는 평가를 받고 있다. 부분적으로, 이러한 평가는 문자 처리에 있어서 함수보다 매크로가 많이 사용되기 때문이다. 프로그래머는 매크로를 사용하면 실행 시간을 상당히 단축할 수 있다고 믿고 있다. 이것이 사실일까?
이 연습 문제는 이러한 것이 사실인지 검사하는 것이다. stdio.h와 ctype.h에 있는 매크로를 사용하는 프로그램을 먼저 작성해 보자.
#include <ctype.h>
#include <stdio.h>
#include <time.h>
int main(void)
{
int c;
printf("Clock ticks: %ld\n", clock()); /* start the clock */
while ((c = getchar()) != EOF)
if (islower(c))
putchar(toupper(c));
else if (isupper(c))
putchar(tolower(c));
else if (isdigit(c))
.....
이 프로그램을 완성하여라. (A.15절에 있는 clock()을 참고하여라.) c가 숫자라면, 문자 x를 출력한다. c가 구두 문자라면, 아무 것도 출력하지 않는다. c가 공백 문자라면, 이것을 두 번 출력한다. main() 함수의 return 문 바로 전에 다음 문장을 삽입하여라.
printf("Clock ticks: %ld\n", clock( )); /* ticks up to now */
이제, 각 매크로를 대응하는 함수로 대치하여 프로그램을 작성하여라. 예를 들면, islower(c) 대신 (islower)(c)를 사용하여라. 두 프로그램으로 문자 파일을 처리하기 위해 재지정을 사용하여라. 파일이 작을 경우는 시스템의 오버헤드 때문에 실행 시간에 큰 차이가 없을 것이다. 그러나 파일이 점점 커질수록, 실행 시간 차이가 생기게 된다. 사실인가? 힌트: 다음과 같이 하면 파일을 화면에 출력하는 시간을 낭비하지 않을 것이다.
pgm < input > output

프로그램을 완성하고나서 message 로그로 테스트를 해 보았습니다. 먼저 ctype.h의 매크로를 이용한 경우 clock tic이 360000 인 반면에 함수를 이용한 경우에는 clock tic이 330000 이 되었습니다. (함수의 경우에는 clock tic이 일정하지 않고 340000인 경우도 있었으며 제시된 clock tic 값은 수차례 테스트해본 평균치입니다.)
적어도 이 예제에서는 함수를 활용하는 경우가 매크로보다 어느정도 빠르다는 결론인데 이거 제대로 테스트한 거 맞습니까?
그렇다면 C는 문자 처리를 위해 좋은 언어라는 평가를 받고 있다. 부분적으로, 이러한 평가는 문자 처리에 있어서 함수보다 매크로가 많이 사용되기 때문이다. 프로그래머는 매크로를 사용하면 실행 시간을 상당히 단축할 수 있다고 믿고 있다. 이것이 사실일까? 이 명제는 거짓입니까?

lsj0713의 이미지

어차피 C 표준이 정의하고 있는 것은 추상적 기계 위에서의 동작 뿐입니다. 동작하는 실제 기계의 특성이나 컴파일러가 최적화하기에 따라서는 얼마든지 다른 결과가 나올 수 있습니다. 일반적으로 매크로고 함수보다 더 빠르다는 믿음을 갖고 있지만, 컴파일러가 어떻게 최적화 하느냐에 따라서는 위와 같은 결과가 나올 수도 있습니다.

제가 생각하기에 C 언어가 문자열을 처리하기에 좋다고 말해지는 것은 포인터 혹은 배열과 같이 적은 비용으로 접근할 수 있는 방법을 제시하기에 그런 것 같습니다. C 언어에서의 문자열 처리는 상당히 직접적이라, 컴퓨터 위에서의 동작과 거의 1:1로 매치됩니다(아예 문자열이라는 자료형이 없으며, string이 '\0'으로 끝나는 문자형의 배열로 정의되고 있습니다).

따라서 프로그래머의 능력에 따라서는 얼마든지 빠르고 효율적인 처리가 가능한 것입니다. 이 문자열을 추상적인 자료형으로 제공할 경우에는 편할지는 모르나 C 같은 방식과 비교할 때 역시 많은 비용(속도, 메모리)이 들게 됩니다.

netj의 이미지

ratmhun wrote:
프로그래머는 매크로를 사용하면 실행 시간을 상당히 단축할 수 있다고 믿고 있다. 이것이 사실일까?

매크로는 컴파일할 때에 실제 코드로 대체가 되기 때문에 함수를 부를 때처럼 스택 프레임 쌓고 내리고 하는 비효율은 없겠죠. inline 함수로 만들고 시험해보면 어떨까요? 비슷하지 않을까요..?

근데, 진짜로 C가 문자열 처리에 좋을까요? 각종 스크립트 언어가 판치는 이 시점에서도? -_-a

nachnine의 이미지

성능상 좋지

소스코드의 생산성은 최악이 아닌가요?

PERL 하고만 비교해도 극단적으로 안 좋다는 걸 알수 있는데요.

죠커의 이미지

ratmhun //
비교에 사용된 매크로와 함수 버전 두개의 소스를 올려주셔야 공정한 비교가 되죠. :-)

nachnine //
생산성이 최악이시라는 주장은 극단적인 것이군요. c가 그렇게 나빴다면 님이 사용하시는 프로그램들은 나오지도 못했을겁니다. :-)

최종호의 이미지

CN wrote:
ratmhun //
비교에 사용된 매크로와 함수 버전 두개의 소스를 올려주셔야 공정한 비교가 되죠. :-)

nachnine //
생산성이 최악이시라는 주장은 극단적인 것이군요. c가 그렇게 나빴다면 님이 사용하시는 프로그램들은 나오지도 못했을겁니다. :-)

ratmhun 님이 언급하신 것처럼
ctype.h 에 정의되어 있는 기능은 대개 매크로로 구현이 되어 있고
이에 해당하는 함수버젼도 제공됩니다.

(표준에서 함수버젼도 제공해야 된다는 것을 얼핏 어디선가 본 것 같은데,
지금 찾아보려니 잘 안보이네요.)

따라서 isupper(c) 와 같이 호출하면 매크로버젼의 isupper(c) 가
사용되고 isupper (c) 와 같이 빈칸을 주거나 (isupper)(c) 와 같이 변형시켜서
매크로 확장이 안되도록 하면 함수버젼이 호출되지요.

저도 테스트를 해 봤습니다.

#include <stdio.h>
#include <ctype.h>
#include <time.h>
#include <sys/times.h>


main(int argc, char **argv)
{
        int     c;
        int     new_c;
        clock_t from_t;
        clock_t to_t;
        int     i;
        struct tms      tms;

        if (argc !=2) {
                fprintf(stderr, "usage: %s <f|m>\n", argv[0]);
                exit(2);
        }
        from_t = times(&tms);
        if (argv[1][0] == 'f') {
            for (i = 0; i < 50000000; i++)
                new_c = (isupper)('a');
        } else {
            for (i = 0; i < 50000000; i++)
                new_c = isupper('a');
        }
        to_t = times(&tms);

        fprintf(stderr, "from = %ld, to = %ld\n", from_t, to_t);
        fprintf(stderr, "elapsed clocks: %ld\n", to_t - from_t);
}

결과는

% a.out f
from = 81154131, to = 81154634
elapsed clocks: 503

% a.out m
from = 81154906, to = 81155097
elapsed clocks: 191

와 같이 매크로를 사용하는 쪽이 2배 이상 빠르게 나왔습니다.

사실 이 코드를 작성하기 전에 다른 코드를 작성했었는데,
그 경우에는 isupper()가 아니라 toupper() 를 사용했었고,
표준입력에서 문자를 읽어 toupper()로 대문자로 바꾼 후
표준출력으로 찍는 프로그램을 작성했었고,
표준입력과 출력은 다 파일로 리다이렉션 시켰고, 입력으로는
30메가짜리 텍스트 파일을 사용했었습니다.

근데, 결과는 함수버젼이 근소하지만 더 빠르게 나왔습니다.
ctype.h 를 살펴보니까 toupper()는 매크로로 정의되어 있지 않고,
매크로 버젼은 _toupper()로 정의되어 있었습니다. (Solaris 8 기준)
결국 둘 다 함수버젼이 사용된 것이었죠.

매크로를 쓰느냐 함수를 쓰느냐는 한번 루프가 수행될 때
또는 해당 함수가 불릴 때 몇 인스트럭션 차이로 소요시간이 차이가 날텐데,
해당 루프에 다른 영향을 줄 수 있는 I/O나 다른 함수, 문장 수행은
정확한 평가에 방해가 될 수 있을것 같습니다.

[/code]

ㅡ,.ㅡ;;의 이미지

nachnine wrote:
성능상 좋지

소스코드의 생산성은 최악이 아닌가요?

PERL 하고만 비교해도 극단적으로 안 좋다는 걸 알수 있는데요.

보는사람 기준에 따라 다르겠지만..

예를들면이렇습니다. 각반에 학생이 30명씩 4반까지 있는 학교가 있다면.

전체 학생수를 구하는데.. 방식이..어떤사람은..

30+30+30+30 이쉽다고 고 말할수 있고

어떤사람은 30X4 가 쉽다고 말할수 있겠죠..

잘생각해보세요... 님이 프로그래밍 하는방식이 어떤방식인가..


----------------------------------------------------------------------------

moonzoo의 이미지

좋다 좋지 않다를 떠나서 일단 불편함이 있습니다.

스트링 객체가 없기 때문에

처리하는데 있어서 직관적이지 못하고

대부분 제공하는 라이브러리(strcpy등..)을 사용해야

하는등...(보통 NUL문자 처리나 초기화 등도 주의해야 하죠..)

프로그래머가 좀더 세세한 부분을 컨트롤 하기에는

좋지만 반대로 말하자면 , 세세한 부분까지 신경써야 하는

불편함을 줄 때도 많은 것 같습니다.

ratmhun의 이미지

CN wrote:
ratmhun //
비교에 사용된 매크로와 함수 버전 두개의 소스를 올려주셔야 공정한 비교가 되죠. :-)

저는 연습문제에 있는 소스를 그대로 사용했습니다.
먼저 매크로를 사용하는 소스는 다음과 같습니다.

Quote:

#include <ctype.h>
#include <stdio.h>
#include <time.h>

int main(void)
{
int c;
printf("Clock ticks: %ld\n", clock()); /* start the clock */
while ((c = getchar()) != EOF)
{
if (islower(c))
putchar(toupper(c));
else if (isupper(c))
putchar(tolower(c));
else if (isdigit(c))
putchar('x');
else if (ispunct(c))
;
else if (isspace(c))
putchar(' ');
}
putchar('\n');
printf("Clock ticks: %ld\n", clock()); /* ticks up to now */
return 0;
}

다음 함수를 사용하는 소스는 다음과 같습니다.

Quote:

#include <ctype.h>
#include <stdio.h>
#include <time.h>

int main(void)
{
int c;
printf("Clock ticks: %ld\n", clock()); /* start the clock */
while ((c = getchar()) != EOF)
{
if ((islower)(c))
putchar((toupper)(c));
else if ((isupper)(c))
putchar((tolower)(c));
else if ((isdigit)(c))
putchar('x');
else if ((ispunct)(c))
;
else if ((isspace)(c))
putchar(' ');
}
putchar('\n');
printf("Clock ticks: %ld\n", clock()); /* ticks up to now */
return 0;
}

답변해주신 모든 분께 감사드립니다. 특별히 직접 소스 까지 만들어 테스트해주신 최종호님, 너무나 고맙습니다.

nachnine의 이미지

저는 C의 생산성이 최악이라고 한 것 아닙니다.
문자열 처리에 관한 코드가 엄청 복잡하다는거죠
C언어에 대해서 안 좋다- 나쁜 언어다 라고 이야기 할 생각은
전혀 없습니다.

다른언어 ( 특히 PERL) 에 비해서 같은 문자 처리 기능을 하는
프로그램을 만들기가 힘들다는 것이죠.

PERL 과 C를 동시에 능숙하게 다를수 있는 사용자라면
어느정도 복잡한 텍스트 처리 요건을 가진 프로그램을 만드는데
당연히 PERL 을 쓸것입니다.

xml을 parsing 하는데만 해도 c에 비해 훨씬 복잡한 코드일텐데요.
Regular Expression을 사용하는데만 해도
별도의 라이브러리가 있지않습니까?

<pineApple>100</pineApple>
100 을 200으로 바꾸는 C 코드의 길이는 얼마입니까?

물론 프로그램의 생산성을 코드의 길이로만 말할순 없겠지만
윗 분 말씀처럼 '신경 써야할 것' 이 너무나 많고 복잡하죠.

전에 간단한 HTML beautifer를 C로 작성하다가
TAG Parsing하는게 너무 복잡해서 PERL을 공부했었던 적이있죠.

그 유명한 TIDY 는 C로 만들어져있지만,
source code의 complexity는 수준급이죠.

marten의 이미지

Programming Pearls (번역서: 생각하는 프로그래밍 : 프로그래밍 본질에 관한 15가지 에세이)의 9번째(?) 칼럼에 보면...

함수 대신 매크로를 사용할 때 속도의 향상이 있을 것이라는 일반적인 C 프로그래머의 믿음을 무너뜨리는 예제가 나옵니다..

한 번 참고해보셔도 좋을 듯 합니다.

http://www.yes24.com/home/pd.asp?SID=dpUaNDK1Rb@QIg9ePA3Jw9JlzTMFuZulf4jcTOox5bkWSUduT1GQmpnya&AK=329227&TABID=1

죠커의 이미지

nachnine wrote:
저는 C의 생산성이 최악이라고 한 것 아닙니다.
문자열 처리에 관한 코드가 엄청 복잡하다는거죠
C언어에 대해서 안 좋다- 나쁜 언어다 라고 이야기 할 생각은
전혀 없습니다.

소스코드의 생산성은 최악이란 문구때문에 그렇게 생각했습니다.

복잡하긴 하지만 C는 잘 엮어서 쓸수가 있어서 효과적인 것 같습니다. 천의무봉의 소스도 만드는게 가능한 것도 C언어의 특징중 하나이죠.

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.