Line Control

#line

#line Linenum Filename
#line Linenum

#line 지시자를 이용하면 __FILE____LINE__ 매크로 값을 임의로 변경할 수 있습니다.

$ gcpp
#line 100 "foo.c"             // 다음 라인부터 __FILE__ 값은 "foo.c" 가 되고
__FILE__ : __LINE__           // __LINE__ 값은 100 이 된다.
__FILE__ : __LINE__
#warning message 111 

#line 200 "bar.c"             // 다음 라인부터 __FILE__ 값은 "bar.c" 가 되고
__FILE__ : __LINE__           // __LINE__ 값은 200 이 된다.
__FILE__ : __LINE__
#warning message 222

#line 300                     // 라인 번호만 설정 
__FILE__ : __LINE__
__FILE__ : __LINE__
#warning message 333
@

foo.c:102:2: warning: #warning message 111 [-Wcpp]
bar.c:202:2: warning: #warning message 222 [-Wcpp]
bar.c:302:2: warning: #warning message 333 [-Wcpp]
"foo.c" : 100
"foo.c" : 101
"bar.c" : 200
"bar.c" : 201
"bar.c" : 300
"bar.c" : 301

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

$ gcc -xc - <<\@
int main() {

#line 1000 "foo.c"           // 다음 라인부터 __FILE__ 값은 "foo.c" 가 되고
    foo("hello");            // __LINE__ 값은 1000 이 된다.

#line 2000 "bar.c"           // 다음 라인부터 __FILE__ 값은 "bar.c" 가 되고
    bar("world");            // __LINE__ 값은 2000 이 된다.
}
@
foo.c: In function ‘main’:
foo.c:1000:5: warning: implicit declaration of function ‘foo’ ...
bar.c:2000:5: warning: implicit declaration of function ‘bar’ ...
. . .

yacc 파서 생성기에 입력으로 plural.y 파일을 사용하면 결과로 plural.c 파일이 생성되는데 이때 plural.y 파일 내용이 plural.c 에서 사용됩니다. 다음을 보면 plural.y 파일 내용이 사용된 곳에서 #line 지시자를 이용해 해당 위치를 지정하는 것을 볼 수 있습니다.

/usr/share/gettext/intl/plural.c 참조 

/* Value type.  */
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED

union YYSTYPE
{
#line 49 "plural.y"              // 다음 라인부터 __FILE__ 값은 "plural.y" 가 되고
                                 // __LINE__ 값은 49 가 된다.
  unsigned long int num;
  enum expression_operator op;
  struct expression *exp;

#line 176 "plural.c"             // 다음 라인부터 __FILE__ 값은 "plural.c" 가 되고
};                               // __LINE__ 값은 176 이 된다.

typedef union YYSTYPE YYSTYPE;
# define YYSTYPE_IS_TRIVIAL 1
# define YYSTYPE_IS_DECLARED 1
#endif
. . .
. . .
  YY_REDUCE_PRINT (yyn);
  switch (yyn)
    {
        case 2:
#line 153 "plural.y" /* yacc.c:1646  */
    {
        if ((yyvsp[0].exp) == NULL)
          YYABORT;
        arg->res = (yyvsp[0].exp);
      }
#line 1365 "plural.c" /* yacc.c:1646  */
    break;

  case 3:
#line 161 "plural.y" /* yacc.c:1646  */
    {
        (yyval.exp) = new_exp_3 (qmop, (yyvsp[-4].exp), (yyvsp[-2].exp), ...
      }
#line 1373 "plural.c" /* yacc.c:1646  */
    break;

  case 4:
#line 165 "plural.y" /* yacc.c:1646  */
    {
        (yyval.exp) = new_exp_2 (lor, (yyvsp[-2].exp), (yyvsp[0].exp));
      }
#line 1381 "plural.c" /* yacc.c:1646  */
    break;
. . .
. . .

Quiz

오류코드 중에 하나인 EWOULDBLOCKEAGAIN 은 어떤 차이가 있을까요?

EWOULDBLOCK 의 의미는 "operation would block" 을 나타내고 EAGAIN 는 "temporary resource shortage made an operation impossible" 을 나타냈는데 현재는 두 매크로 값을 구분 없이 같은 값을 사용하고 있습니다.

$ header-macro errno.h -e EWOULDBLOCK       // Resource temporarily unavailable
11

$ header-macro errno.h -e EAGAIN            // Resource temporarily unavailable
11

$ header-macro errno.h -s EWOULDBLOCK
#define EWOULDBLOCK EAGAIN

하지만 2002 년 이전의 AIX 4.3,5.1 HP-UX 11.22 OSF1 같은 운영체제에서는 다른 값을 사용했다고 합니다. 이때도 매크로 값은 다르지만 같은 의미로 사용됐으므로 이와 같은 구 버전의 OS 도 지원하려면 다음 세 번째와 같이 작성하면 되고 그렇지 않을 경우는 첫 번째와 두 번째는 차이가 없습니다.

  if ( errno == EAGAIN ) { ...

  if ( errno == EWOULDBLOCK ) { ...

  if ( errno == EWOULDBLOCK || errno == EAGAIN ) { ...

2 .

socket 함수의 원형은 아래와 같은데요. 여기서 세 번째 인수인 protocol 값으로 0 을 사용하는 경우가 많습니다. 여기서 0 은 어떤 값일까요 ?

int socket( int domain, int type, int protocol );

int sockfd = socket( AF_INET, SOCK_STREAM, 0 );
int sockfd = socket( AF_INET, SOCK_DGRAM, 0 );

int sockfd = socket( AF_UNIX, SOCK_STREAM, 0 );

AF_INETprotocol 값으로 사용되는 0IPPROTO_IP 를 나타냅니다. 여기서 IPPROTO_IP 는 매크로가 아니고 enum 입니다. 그러니까 0 대신에 IPPROTO_IP 를 입력한 것과 동일한 것이 됩니다. protocol 값이 IPPROTO_IP 이면 socket 함수가 자동으로 domain 과 type 을 보고 판단하여 SOCK_STREAM 일 경우는 protocol 값으로 IPPROTO_TCP 를 사용하고 SOCK_DGRAM 일 경우는 IPPROTO_UDP 를 사용합니다. AF_UNIX ( unix domain socket ) 같은 경우는 local 접속에 사용되는 것으로 따로 protocol 이 사용되지 않으므로 0 을 사용합니다. 그 외에는 아래 세 번째와 같이 직접 protocol 값을 적어주어야 합니다.

$ header-enum netinet/in.h -s IPPROTO_IP       # 매크로가 아니고 enum 값이다.
enum {
    IPPROTO_IP = 0,
    IPPROTO_ICMP = 1,
    . . .
$ header-macro netinet/in.h -s IPPROTO_IP
#define IPPROTO_IP IPPROTO_IP
#define IPPROTO_IPIP IPPROTO_IPIP
#define IPPROTO_IPV6 IPPROTO_IPV6

# 직접 protocol 값을 적어주어야 한다.
int sockfd = socket( AF_INET, SOCK_STREAM, IPPROTO_SCTP)