óÀ½, ÀÌÀü, ´ÙÀ½, ¸¶Áö¸· Àý·Î °¡±â, ¸ñÂ÷.
This section describes some of the routines used in the C++ front-end.
will get the related binfo.
Supposedly (according to Tiemann) most of the breadth first searching
done, like in
¿ø¹®½ÃÀÛ
Limitations of g++
Routines
build_vtable
and prepare_fresh_vtable
is used only within
the `cp-class.c' file, and only in finish_struct
and
modify_vtable_entries
.
build_vtable
, prepare_fresh_vtable
, and
finish_struct
are the only routines that set DECL_VPARENT
.
finish_struct
can steal the virtual function table from parents,
this prohibits related_vslot from working. When finish_struct steals,
we know that
get_binfo (DECL_FIELD_CONTEXT (CLASSTYPE_VFIELD (t)), t, 0)
layout_basetypes
does something with the VIRTUALS.
get_base_distance
and in get_binfo
was not
because of any design decision. I have since found out the at least one
part of the compiler needs the notion of depth first binfo searching, I
am going to try and convert the whole thing, it should just work. The
term left-most refers to the depth first left-most node. It uses
MAIN_VARIANT == type
as the condition to get left-most, because
the things that have BINFO_OFFSET
s of zero are shared and will
have themselves as their own MAIN_VARIANT
s. The non-shared right
ones, are copies of the left-most one, hence if it is its own
MAIN_VARIANT
, we know it IS a left-most one, if it is not, it is
a non-left-most one.
get_base_distance
's path and distance matters in its use in:
prepare_fresh_vtable
(the code is probably wrong)
init_vfields
Depends upon distance probably in a safe way,
build_offset_ref might use partial paths to do further lookups,
hack_identifier is probably not properly checking access.
get_first_matching_virtual
probably should check for
get_base_distance
returning -2.
resolve_offset_ref
should be called in a more deterministic
manner. Right now, it is called in some random contexts, like for
arguments at build_method_call
time, default_conversion
time, convert_arguments
time, build_unary_op
time,
build_c_cast
time, build_modify_expr
time,
convert_for_assignment
time, and
convert_for_initialization
time.
But, there are still more contexts it needs to be called in, one was the
ever simple:
if (obj.*pmi != 7)
...
Seems that the problems were due to the fact that TREE_TYPE
of
the OFFSET_REF
was not a OFFSET_TYPE
, but rather the type
of the referent (like INTEGER_TYPE
). This problem was fixed by
changing default_conversion
to check TREE_CODE (x)
,
instead of only checking TREE_CODE (TREE_TYPE (x))
to see if it
was OFFSET_TYPE
.
Implementation Specifics
current_member_init_list
contains the list of
mem-initializers specified in a constructor declaration. For example:
foo::foo() : a(1), b(2) {}
will initialize `a' with 1 and `b' with 2.
expand_member_init
places each initialization (a with 1) on the
global list. Then, when the fndecl is being processed,
emit_base_init
runs down the list, initializing them. It used to
be the case that g++ first ran down current_member_init_list
,
then ran down the list of members initializing the ones that weren't
explicitly initialized. Things were rewritten to perform the
initializations in order of declaration in the class. So, for the above
example, `a' and `b' will be initialized in the order that
they were declared:
class foo { public: int b; int a; foo (); };
Thus, `b' will be initialized with 2 first, then `a' will be
initialized with 1, regardless of how they're listed in the mem-initializer.
explicit
on a constructor is used by grokdeclarator
to set the field DECL_NONCONVERTING_P
. That value is used by
build_method_call
and build_user_type_conversion_1
to decide
if a particular constructor should be used as a candidate for conversions.
Glossary
is_normal
depends upon this.
FIELD_DECL
s that are pointer types that point to
vtables. See also vtable and vfield.
¿ø¹®³¡
º» ÀýÀº C++ front-end¿¡¼ Á¾Á¾ »ç¿ëµÇ´Â ¸î°¡Áö ·çƾ(routine)À» ±â¼úÇÑ´Ù.
build_vtable
°ú prepare_fresh_vtable
´Â `cp-class.c' ÆÄÀϳ»¿¡¼¸¸ »ç¿ëµÈ´Ù. ±×¸®°í finish_struct
°ú
modify_vtable_entries
¿¡¼¸¸ »ç¿ëµÈ´Ù.
build_vtable
, prepare_fresh_vtable
,
finish_struct
´Â DECL_VPARENT
¸¦ ¼³Á¤ÇÏ´Â À¯ÀÏÇÑ ·çƾÀÌ´Ù.
finish_struct
´Â »óÀ§·ÎºÎÅÍ °¡»óÇÔ¼öÇ¥(virtual function table)¸¦ ÈÉÃÄ¿Ã ¼ö ÀÖ´Ù. ÀÌ°ÍÀº related_vslotÀÌ µ¿ÀÛÇÏ´Â °ÍÀ» ¹æÁöÇÑ´Ù. finish_struct°¡ Ç¥¸¦ ÈÉÃÄ¿Ã ¶§,
get_binfo (DECL_FIELD_CONTEXT (CLASSTYPE_VFIELD (t)), t, 0)
°¡ °ü·Ã binfo¸¦ ¾ò´Â´Ù´Â °ÍÀ» ¾È´Ù.
layout_basetypes
´Â VIRTUALS·Î ¹º°¡¸¦ ÇÑ´Ù.
Supposedly (according to Tiemann) most of the breadth first searching
done, like in get_base_distance
and in get_binfo
was not
because of any design decision. I have since found out the at least one
part of the compiler needs the notion of depth first binfo searching, I
am going to try and convert the whole thing, it should just work. The
term left-most refers to the depth first left-most node. It uses
MAIN_VARIANT == type
as the condition to get left-most, because
the things that have BINFO_OFFSET
s of zero are shared and will
have themselves as their own MAIN_VARIANT
s. The non-shared right
ones, are copies of the left-most one, hence if it is its own
MAIN_VARIANT
, we know it IS a left-most one, if it is not, it is
a non-left-most one.
´ÙÀ½°ú °°Àº »ç¿ë¿¡¼ get_base_distance
ÀÇ °æ·Î¿Í °Å¸® ¹®Á¦:
prepare_fresh_vtable
(Äڵ尡 ¾î¼¸é Ʋ¸°´Ù)
init_vfields
´Â ¾ÈÀüÇÑ ¹æ¹ýÀ¸·Î ¾î¼¸é °Å¸®¿¡ ÀÇÁ¸ÇÑ´Ù. build_offset_ref´Â ÈξÀ ´õ ¸¹ÀÌ ·è¾÷(lookup)ÇϱâÀ§ÇØ ºÎºÐ °æ·Î(partial path)¸¦ »ç¿ëÇÒÁöµµ ¸ð¸¥´Ù. hack_identifier´Â ¾Æ¸¶ Á¢¼ÓÀ» ÀûÀýÈ÷ °Ë»çÇÏÁö ¸øÇÒ°ÍÀÌ´Ù.
get_first_matching_virtual
Àº -2¸¦ ¹ÝȯÇÏ´Â get_base_distance
¿¡ ´ëÇØ ¾î¼¸é °Ë»çÇؾßÇÑ´Ù.
resolve_offset_ref
Àº Á»´õ °áÁ¤ÀûÀÎ ¹æ¹ýÀ¸·Î ºÒ·ÁÁ®¾ß ÇÑ´Ù. ¹Ù·Î ±×°ÍÀº build_method_call
½Ã°£, default_conversion
½Ã°£, convert_arguments
½Ã°£, build_unary_op
½Ã°£, build_c_cast
½Ã°£, build_modify_expr
½Ã°£, convert_for_assignment
½Ã°£, convert_for_initialization ½Ã°£¿¡¼ ÀÎÀÚ¿¡ ´ëÇÑ °Íó·³, ¸î°¡Áö ÀÓÀÇ ¹®¸Æ(random context)¿¡¼ ºÒ·ÁÁø´Ù. ±×·¯³ª ¿©ÀüÈ÷ ºÒ·ÁÁ®¾ßÇÏ´Â ´õ ¸¹Àº ¹®¸ÆÀÌ ÀÖ´Ù. ÇÑ°¡Áö´Â ¿©ÀüÈ÷ °£´ÜÇß¾ú´Ù:
if (obj.*pmi != 7)
...
¹®Á¦Á¡µéÀÌ OFFSET_REF
ÀÇ TREE_TYPE
ÀÌ OFFSET_TYPE
ÀÌ ¾Æ´Ï°í, ¿ÀÈ÷·Á (INTEGER_TYPE
°ú °°Àº) Áö½Ã(referent) ÇüÀ̶ó´Â »ç½Ç¿¡ ±âÀÎÇÏ´Â °Íó·³ º¸ÀδÙ.
ÀÌ ¹®Á¦´Â OFFSET_TYPE
ÀÎÁö¸¦ º¸±âÀ§ÇÑ TREE_CODE (TREE_TYPE (x))
¸¸ ¿ÀÁ÷ °Ë»çÇϴ´ë½Å, OFFSET_CODE (x)
¸¦ °Ë»çÇϱâÀ§ÇÑ default_conversion
À» º¯°æÇÔÀ¸·Î½á °íÃÄÁ³´Ù.
current_member_init_list
´Â »ý¼ºÀÚ ¼±¾ð¿¡ ÁöÁ¤µÈ mem-initializerÀÇ ¸ñ·ÏÀ» Æ÷ÇÔÇÑ´Ù. ¿¹¸¦ µé¸é:
foo::foo() : a(1), b(2) {}ÀÌ°ÍÀº `a'¸¦ 1·Î, `b'¸¦ 2·Î ÃʱâÈ ÇÒ °ÍÀÌ´Ù.
expand_member_init
´Â Àü¿ª ¸ñ·Ï»ó¿¡ °¢ ÃʱⰪ(a¸¦ 1·Î)À» À§Ä¡½ÃŲ´Ù.
±×·±´ÙÀ½ fndeclÀÌ Ã³¸®µÇ°í ÀÖÀ»¶§, emit_base_init
´Â ±×°ÍµéÀ» ÃʱâÈÇÏ¸é¼ ¸ñ·ÏÀ» ÈÈ¾î ³»·Á°£´Ù.
g++Àº ¿ì¼± current_member_init_list
¸¦ ÈÈ¾î ³»·Á°¡´Â °æ¿ì¿¡ »ç¿ëµÈ´Ù. ±×´ÙÀ½ ¸íÈ®È÷ ÃʱâȵÇÁö ¾ÊÀº °ÍµéÀ» ÃʱâÈÇÒ ¸â¹öÀÇ ¸ñ·ÏÀ» ÈÈ¾î ³»·Á°£´Ù.
±×°ÍµéÀº Ŭ·¡½º¿¡¼ ¼±¾ðÀ» À§ÇØ Ãʱâȸ¦ ¼öÇàÇϵµ·Ï ´Ù½Ã ½áÁ®¾ß ÇÑ´Ù. ±×·¡¼ À§ÀÇ ¿¹¿¡¼, `a'¿Í `b'´Â ±×µéÀÌ ¼±¾ðµÇ±â À§Çؼ Ãʱâ鵃 °ÍÀÌ´Ù:
class foo { public: int b; int a; foo (); };ÀÌ·¸µí `b'´Â ¿ì¼± 2·Î Ãʱâ鵃 °ÍÀÌ´Ù. ±×¸®°í³ª¼ `a'°¡ 1·Î Ãʱâ鵃 °ÍÀÌ´Ù. ±×°ÍµéÀÌ mem-initializer¿¡ ¾î¶»°Ô ÀûÇôÀÖ´ø°£¿¡ ¸»ÀÌ´Ù.
explicit
ÀÇ »ç¿ëÀº Çʵå DECL_NONCONVERTING_P
¸¦ ¼³Á¤Çϱâ À§ÇØ grokdeclarator
¿¡ ÀÇÇØ »ç¿ëµÈ´Ù.
±× °ªÀº Ưº°ÇÑ »ý¼ºÀÚ°¡ º¯È¯À» À§ÇÑ Áö¿øÀÚ·Î½á »ç¿ëµÇ¾ßÇÏ´ÂÁö¸¦ °áÁ¤ÇϱâÀ§ÇØ build_method_call
°ú build_user_type_conversion_1
¿¡ ÀÇÇØ »ç¿ëµÈ´Ù.
is_normal
Àº ÀÌ¿¡ ´Þ·ÁÀÖ´Ù.
FIELD_DECL
ÀÌ´Ù. vtable¿Í vfield¸¦ º¸¶ó.
This section describes some of the macros used on trees. The list should be alphabetical. Eventually all macros should be documented here.
BINFO_BASETYPES
BINFO_INHERITANCE_CHAIN
Z ZbY least derived | Y YbX | X Xb most derived TYPE_BINFO (X) == Xb BINFO_INHERITANCE_CHAIN (Xb) == YbX BINFO_INHERITANCE_CHAIN (Yb) == ZbY BINFO_INHERITANCE_CHAIN (Zb) == 0Not sure is the above is really true, get_base_distance has is point towards the most derived type, opposite from above. Set by build_vbase_path, recursive_bounded_basetype_p, get_base_distance, lookup_field, lookup_fnfields, and reverse_path. What things can this be used on: TREE_VECs that are binfos
BINFO_OFFSET
BINFO_VIRTUALS
BINFO_VTABLE
BLOCK_SUPERCONTEXT
CLASSTYPE_TAGS
CLASSTYPE_METHOD_VEC
CLASSTYPE_VFIELD
DECL_CLASS_CONTEXT
struct A { virtual int f (); }; struct B : A { int f (); }; DECL_CONTEXT (A::f) == A DECL_CLASS_CONTEXT (A::f) == A DECL_CONTEXT (B::f) == A DECL_CLASS_CONTEXT (B::f) == BHas values of: RECORD_TYPEs, or UNION_TYPEs What things can this be used on: TYPE_DECLs, _DECLs
DECL_CONTEXT
VAR_DECLs that are virtual function tables _DECLs
DECL_FIELD_CONTEXT
FIELD_DECLs that are virtual function pointers FIELD_DECLs
DECL_NAME
0 for things that don't have names IDENTIFIER_NODEs for TYPE_DECLs
DECL_IGNORED_P
DECL_VIRTUAL_P
DECL_VPARENT
DECL_FCONTEXT
DECL_REFERENCE_SLOT
DECL_VINDEX
DECL_SOURCE_FILE
DECL_SOURCE_LINE
0 for an undefined label 0 for TYPE_DECLs that are internally generated 0 for FUNCTION_DECLs for functions generated by the compiler (not yet, but should be) 0 for "magic" arguments to functions, that the user has no control over
TREE_USED
TREE_ADDRESSABLE
TREE_COMPLEXITY
TREE_HAS_CONSTRUCTOR
TREE_PRIVATE
TREE_PROTECTED
TYPE_BINFO
TYPE_BINFO_BASETYPES
TYPE_BINFO_VIRTUALS
TYPE_BINFO_VTABLE
TYPE_NAME
0 for things that don't have names. should be IDENTIFIER_NODE for RECORD_TYPEs UNION_TYPEs and ENUM_TYPEs. TYPE_DECL for RECORD_TYPEs, UNION_TYPEs and ENUM_TYPEs, but shouldn't be. TYPE_DECL for typedefs, unsure why.What things can one use this on:
TYPE_DECLs RECORD_TYPEs UNION_TYPEs ENUM_TYPEsHistory: It currently points to the TYPE_DECL for RECORD_TYPEs, UNION_TYPEs and ENUM_TYPEs, but it should be history soon.
TYPE_METHODS
CLASSTYPE_METHOD_VEC
. Chained together with
TREE_CHAIN
. `dbxout.c' uses this to get at the methods of a
class.
TYPE_DECL
typedef int foo;
is
seen.
DECL_SOURCE_LINE identifies what source line number in the
source file the declaration was found at. A value of 0
indicates that this TYPE_DECL is just an internal binding layer
marker, and does not correspond to a user supplied typedef.
DECL_SOURCE_FILE
TYPE_FIELDS
TREE_CHAIN
) of member types of a class. The
list can contain TYPE_DECL
s, but there can also be other things
in the list apparently. See also CLASSTYPE_TAGS
.
TYPE_VIRTUAL_P
FIELD_DECL
or a VAR_DECL
, indicates it is
a virtual function table or a pointer to one. When used on a
FUNCTION_DECL
, indicates that it is a virtual function. When
used on an IDENTIFIER_NODE
, indicates that a function with this
same name exists and has been declared virtual.
When used on types, it indicates that the type has virtual functions, or
is derived from one that does.
Not sure if the above about virtual function tables is still true. See
also info on DECL_VIRTUAL_P
.
What things can this be used on:
FIELD_DECLs, VAR_DECLs, FUNCTION_DECLs, IDENTIFIER_NODEs
VF_BASETYPE_VALUE
finish_base_struct
time.
What things can this be used on:
TREE_LISTs that are vfields
History:
This field was used to determine if a virtual function table's
slot should be filled in with a certain virtual function, by
checking to see if the type returned by VF_BASETYPE_VALUE was a
parent of the context in which the old virtual function existed.
This incorrectly assumes that a given type _could_ not appear as
a parent twice in a given inheritance lattice. For single
inheritance, this would in fact work, because a type could not
possibly appear more than once in an inheritance lattice, but
with multiple inheritance, a type can appear more than once.
VF_BINFO_VALUE
TREE_VIA_VIRTUAL
on result to find out if it is a virtual base class. Related to the
binfo found by
get_binfo (VF_BASETYPE_VALUE (vfield), t, 0)where `t' is the type that has the given vfield.
get_binfo (VF_BASETYPE_VALUE (vfield), t, 0)will return the binfo for the given vfield. May or may not be set at
modify_vtable_entries
time. Set at
finish_base_struct
time.
What things can this be used on:
TREE_LISTs that are vfields
VF_DERIVED_VALUE
finish_base_struct
time.
What things can this be used on:
TREE_LISTs that are vfields
VF_NORMAL_VALUE
finish_base_struct
time.
What things can this be used on:
TREE_LISTs that are vfields
WRITABLE_VTABLES
º» ÀýÀº Æ®¸®(tree)¿¡¼ »ç¿ëµÈ ¸î°¡Áö ¸ÅÅ©·Î¸¦ ±â¼úÇÑ´Ù. ¸ñ·ÏÀº ¾ËÆĺª¼øÀ̾î¾ß ÇÑ´Ù. °á±¹ ¸ðµç ¸ÅÅ©·Î´Â ¿©±â¿¡ ¹®¼ÈµÇ¾î¾ß ÇÑ´Ù.
BINFO_BASETYPES
BINFO_INHERITANCE_CHAIN
Z ZbY least derived | Y YbX | X Xb most derived TYPE_BINFO (X) == Xb BINFO_INHERITANCE_CHAIN (Xb) == YbX BINFO_INHERITANCE_CHAIN (Yb) == ZbY BINFO_INHERITANCE_CHAIN (Zb) == 0À§ÀÇ °ÍÀÌ Á¤¸» »ç½ÇÀÎÁö´Â È®½ÇÄ¡ ¾Ê´Ù. get_base_distance´Â À§¿Í ¹Ý´ë·Î °¡Àå ¸¸Èþ ÆÄ»ýµÈ Çü(most derived type)ÂÊÀ» °¡¸£Å²´Ù. build_vbase_path, recursive_bounded_basetype_p, get_base_distance, lookup_field, lookup_fnfields, reverse_path ¸¦ ¸ð¾ÆµÎ¾î¶ó. ÀÌ°ÍÀº ¾î¶² °Íµé¿¡°Ô »ç¿ëµÉ ¼ö Àִ°¡: binfoÀÎ TREE_VEC
BINFO_OFFSET
BINFO_VIRTUALS
BINFO_VTABLE
BLOCK_SUPERCONTEXT
CLASSTYPE_TAGS
CLASSTYPE_METHOD_VEC
CLASSTYPE_VFIELD
DECL_CLASS_CONTEXT
struct A { virtual int f (); }; struct B : A { int f (); }; DECL_CONTEXT (A::f) == A DECL_CLASS_CONTEXT (A::f) == A DECL_CONTEXT (B::f) == A DECL_CLASS_CONTEXT (B::f) == B´ÙÀ½ÀÇ °ªÀ» °¡Áø´Ù: RECORD_TYPE ¶Ç´Â UNION_TYPE ÀÌ°ÍÀº ¾î¶² °Íµé¿¡°Ô »ç¿ëµÉ ¼ö Àִ°¡: TYPE_DECL, _DECL
DECL_CONTEXT
°¡»ó ÇÔ¼öÇ¥ÀÎ VAR_DECL _DECL
DECL_FIELD_CONTEXT
°¡»ó ÇÔ¼öÆ÷ÀÎÅÍÀÎ FIELD_DECL FIELD_DECL
DECL_NAME
À̸§À» °¡ÁöÁö ¾Ê´Â °Í¿¡ ´ëÇØ 0 TYPE_DECL¿¡ ´ëÇØ IDENTIFIER_NODE
DECL_IGNORED_P
DECL_VIRTUAL_P
DECL_VPARENT
DECL_FCONTEXT
DECL_REFERENCE_SLOT
DECL_VINDEX
DECL_SOURCE_FILE
DECL_SOURCE_LINE
Á¤ÀÇ µÇÁö ¾ÊÀº ¶óº§(label)¿¡ ´ëÇØ 0 ³»ºÎÀûÀ¸·Î »ý¼ºµÈ TYPE_DECL¿¡ ´ëÇØ 0 ÄÄÆÄÀÏ·¯¿¡ ÀÇÇØ »ý¼ºµÈ ÇÔ¼ö¿¡ ´ëÇÑ FUNCTION_DECL¿¡ ´ëÇØ 0 (¾ÆÁ÷ ¾Æ´Ï´Ù, ±×·¯³ª ÀÖ¾î¾ß ÇÑ´Ù.) »ç¿ëÀÚ°¡ °ü¸®ÇÒ ¼ö ¾ø´Â ÇÔ¼ö¿¡ ´ëÇÑ ÀÎÀÚ "magic"¿¡ ´ëÇØ 0
TREE_USED
TREE_ADDRESSABLE
TREE_COMPLEXITY
TREE_HAS_CONSTRUCTOR
TREE_PRIVATE
TREE_PROTECTED
TYPE_BINFO
TYPE_BINFO_BASETYPES
TYPE_BINFO_VIRTUALS
TYPE_BINFO_VTABLE
TYPE_NAME
À̸§À» °¡ÁöÁö ¾Ê´Â °Í¿¡ ´ëÇØ 0. RECORD_TYPE, UNION_TYPE, ENUM_TYPE¿¡ ´ëÇØ IDENTIFIER_NODEÀ̾î¾ß ÇÏÁö¸¸, RECORD_TYPE, UNION_TYPE, ENUM_TYPE¿¡ ´ëÇØ TYPE_DECLÀ̾ ¾ÈµÈ´Ù. typedefs¿¡ ´ëÇØ TYPE_DECL, ¿Ö ±×·±Áö È®½ÇÄ¡ ¾Ê´Ù.ÀÌ°ÍÀº ¾î¶² °Íµé¿¡°Ô »ç¿ëµÉ ¼ö Àִ°¡:
TYPE_DECL RECORD_TYPE UNION_TYPE ENUM_TYPEHistory: ±×°ÍÀº ÀϹÝÀûÀ¸·Î RECORD_TYPE¿¡ ´ëÇÑ TYPE_DECL, UNION_TYPE, ENUM_TYPE¸¦ Áö½ÃÇÑ´Ù. ±×·¯³ª °ð history°¡ µÈ´Ù.
TYPE_METHODS
CLASSTYPE_METHOD_VEC
¿¡ ´ëÇÑ µ¿ÀǾî. TREE_CHAIN
°ú ÇÔ²² ¹¿©ÀÖ´Ù. `dbxout.c'´Â Ŭ·¡½ºÀÇ ¸Þ¼µå¸¦ ¾ò±âÀ§ÇØ ÀÌ°ÍÀ» ÀÌ¿ëÇÑ´Ù.
TYPE_DECL
typedef int foo;
°¡ º¸¿©Áú ¶§, foo°¡ DECL_NAME ½½·Ô¿¡¼ ¹ß°ßµÈ´Ù.
DECL_SOURCE_LINE´Â ¼±¾ðÀÌ ¹ß°ßµÈ ¿ø½Ã ÆÄÀϳ»¿¡¼ ¾î¶² source line number¿Í µ¿ÀÏÇÏ´Ù.
0ÀÇ °ªÀº ÀÌ TYPE_DECLÀÌ ´ÜÁö ³»ºÎÀÇ binding layer markerÀÏ »ÓÀ̶ó´Â °ÍÀ» °¡¸£ÄÑÁØ´Ù. ±×¸®°í user supplied typedef¿Í ÀÏÄ¡ÇÏÁö ¾Ê´Â´Ù.
DECL_SOURCE_FILE
TYPE_FIELDS
TREE_CHAIN
À» ÅëÇÑ) ¸µÅ© ¸ñ·Ï. ¸ñ·ÏÀº TYPE_DECL
À» Æ÷ÇÔÇÒ ¼ö ÀÖ´Ù. ±×·¯³ª ºÐ¸íÈ÷ ¸ñ·Ï¿¡ ´Ù¸¥ °ÍµéÀÌ ÀÖÀ» ¼öµµ ÀÖ´Ù. ¶ÇÇÑ CLASSTYPE_TAGS
¸¦ º¸¶ó.
TYPE_VIRTUAL_P
FIELD_DECL
À̳ª VAR_DECL
»ó¿¡¼ »ç¿ëµÈ Ç÷¡±×.
±×°ÍÀÌ °¡»ó ÇÔ¼öÇ¥¶ó´Â °ÍÀ» °¡¸£Å°°Å³ª Æ÷ÀÎÅÍÀÓÀ» °¡¸£Å²´Ù.
FUNCTION_DECL
¿¡¼ »ç¿ëµÉ ¶§, ±×°ÍÀÌ °¡»ó ÇÔ¼ö¶ó´Â °ÍÀ» °¡¸£Å²´Ù.
IDENTIFIER_NODE
¿¡¼ »ç¿ëµÉ ¶§, °°Àº À̸§À» °¡Áø ÇÔ¼ö°¡ Á¸ÀçÇÏ°í virtual·Î ¼±¾ðµÇ¾úÀ½À» °¡¸£Å²´Ù.
Çü¿¡ »ç¿ëµÉ ¶§, Çü(type)ÀÌ °¡»ó ÇÔ¼ö¸¦ °¡Áø´Ù´Â °ÍÀ» °¡¸£Å²´Ù.
¶Ç´Â ±×·¸°Ô ÇàÇÏ´Â °ÍÀ¸·Î ºÎÅÍ ÆÄ»ýµÈ´Ù. À§ÀÇ °¡»ó ÇÔ¼öÇ¥¿¡ ´ëÇÑ °ÍÀº ¾ÆÁ÷±îÁö »ç½ÇÀÎÁö ¾Æ´ÑÁöÈ®½ÇÄ¡ ¾Ê´Ù.
¶ÇÇÑ DECL_VIRTUAL_P
»óÀÇ info¸¦ º¸¶ó.
ÀÌ°ÍÀº ¾î¶² °Íµé¿¡°Ô »ç¿ëµÉ ¼ö Àִ°¡:
FIELD_DECL, VAR_DECL, FUNCTION_DECL, IDENTIFIER_NODE
VF_BASETYPE_VALUE
finish_base_struct
½Ã°£¿¡ ¼³Á¤ÇÑ´Ù.
ÀÌ°ÍÀº ¾î¶² °Íµé¿¡°Ô »ç¿ëµÉ ¼ö Àִ°¡:
vfieldÀÎ TREE_LIST
Histroy:
ÀÌ Çʵå´Â VF_BASETYPE_VALUE¿¡ ÀÇÇØ ¹ÝȯµÈ ÇüÀÌ ¿¹Àü °¡»ó ÇÔ¼ö°¡ Á¸ÀçÇß´ø ¹®¸Æ(context)ÀÇ ºÎ¸ð¿´´ÂÁö¸¦ ¾Ë¾Æº¸±â À§ÇØ °Ë»çÇÔÀ¸·Î½á, °¡»ó ÇÔ¼öÇ¥ÀÇ ½½·ÔÀÌ ¾î¶² °¡»ó ÇÔ¼ö·Î ä¿öÁ®¾ß ÇÒÁö ¾Æ´ÒÁö¸¦ °áÁ¤Çϴµ¥ »ç¿ëµÇ°ï Çß´Ù. ÀÌ°ÍÀº ÁÖ¾îÁø Çü _could_ °¡ ÁÖ¾îÁø »ó¼Ó lattice¿¡¼ ºÎ¸ð·Î½á µÎ¹øº¸ÀÌÁö ¾Ê´Â´Ù¶ó°í ºÎÁ¤È®ÇÏ°Ô °¡Á¤ÇÑ´Ù.
´Üµ¶ »ó¼Ó¿¡ ´ëÇØ ÀÌ°ÍÀº »ç½Ç»ó µ¿ÀÛÇÒ °ÍÀÌ´Ù. ¿Ö³ÄÇϸé ÇüÀº »ó¼Ó lattice¿¡¼ ¾Æ¸¶µµ Çѹø ÀÌ»ó º¸ÀÏ ¼ö ¾ø±â ¶§¹®ÀÌ´Ù. ±×·¯³ª ´ÙÁß »ó¼ÓÀ» °¡Áø ÇüÀº ÇѹøÀÌ»ó º¸ÀÏ ¼ö ÀÖ´Ù.
VF_BINFO_VALUE
TREE_VIA_VIRTUAL
À» »ç¿ëÇÒ ¼ö ÀÖ´Ù.
binfo¿¡ °üÇÑ °ÍÀº ´ÙÀ½¿¡ ÀÇÇØ ¹ß°ßµÈ´Ù.
get_binfo (VF_BASETYPE_VALUE (vfield), t, 0)¿©±â¼ `t'´Â ÁÖ¾îÁø vfield¸¦ °¡Áø ÇüÀÌ´Ù.
get_binfo (VF_BASETYPE_VALUE (vfield), t, 0)ÀÌ°ÍÀº ÁÖ¾îÁø vfield¿¡ ´ëÇØ binfo¸¦ ¹ÝȯÇÒ °ÍÀÌ´Ù.
modify_vtable_entries
½Ã°£¿¡ ¼³Á¤ÇÑ´Ù. finish_base_struct
½Ã°£¿¡ ¼³Á¤ÇÑ´Ù.
ÀÌ°ÍÀº ¾î¶² °Íµé¿¡°Ô »ç¿ëµÉ ¼ö Àִ°¡:
vfieldÀÎ TREE_LIST
VF_DERIVED_VALUE
finish_base_struct
½Ã°£¿¡ ¼³Á¤ÇÑ´Ù.
ÀÌ°ÍÀº ¾î¶² °Íµé¿¡°Ô »ç¿ëµÉ ¼ö Àִ°¡:
vfieldÀÎ TREE_LIST
VF_NORMAL_VALUE
finish_base_struct
½Ã°£¿¡ ¼³Á¤ÇÑ´Ù.
ÀÌ°ÍÀº ¾î¶² °Íµé¿¡°Ô »ç¿ëµÉ ¼ö Àִ°¡:
vfieldÀÎ TREE_LIST
WRITABLE_VTABLES
Whenever seemingly normal code fails with errors like
syntax error at `\{'
, it's highly likely that grokdeclarator is
returning a NULL_TREE for whatever reason.
It should never be that case that trees are modified in-place by the back-end, unless it is guaranteed that the semantics are the same no matter how shared the tree structure is. `fold-const.c' still has some cases where this is not true, but rms hypothesizes that this will never be a problem.
A template is represented by a TEMPLATE_DECL
. The specific
fields used are:
DECL_TEMPLATE_RESULT
DECL_TEMPLATE_PARMS
The generic decl is parsed as much like any other decl as possible, given the parameterization. The template decl is not built up until the generic decl has been completed. For template classes, a template decl is generated for each member function and static data member, as well.
Template members of template classes are represented by a TEMPLATE_DECL for the class' parameters around another TEMPLATE_DECL for the member's parameters.
All declarations that are instantiations or specializations of templates refer to their template and parameters through DECL_TEMPLATE_INFO.
How should I handle parsing member functions with the proper param decls? Set them up again or try to use the same ones? Currently we do the former. We can probably do this without any extra machinery in store_pending_inline, by deducing the parameters from the decl in do_pending_inlines. PRE_PARSED_TEMPLATE_DECL?
If a base is a parm, we can't check anything about it. If a base is not a parm, we need to check it for name binding. Do finish_base_struct if no bases are parameterized (only if none, including indirect, are parms). Nah, don't bother trying to do any of this until instantiation -- we only need to do name binding in advance.
Always set up method vec and fields, inc. synthesized methods. Really? We can't know the types of the copy folks, or whether we need a destructor, or can have a default ctor, until we know our bases and fields. Otherwise, we can assume and fix ourselves later. Hopefully.
The function compute_access returns one of three values:
access_public
access_protected
access_private
DECL_ACCESS is used for access declarations; alter_access creates a list of types and accesses for a given decl.
Formerly, DECL_{PUBLIC,PROTECTED,PRIVATE} corresponded to the return codes of compute_access and were used as a cache for compute_access. Now they are not used at all.
TREE_PROTECTED and TREE_PRIVATE are used to record the access levels granted by the containing class. BEWARE: TREE_PUBLIC means something completely unrelated to access control!
The C++ front-end uses a call-back mechanism to allow functions to print
out reasonable strings for types and functions without putting extra
logic in the functions where errors are found. The interface is through
the cp_error
function (or cp_warning
, etc.). The
syntax is exactly like that of error
, except that a few more
conversions are supported:
There is some overlap between these; for instance, any of the node
options can be used for printing an identifier (though only %D
tries to decipher function names).
For a more verbose message (class foo
as opposed to just foo
,
including the return type for functions), use %#c
.
To have the line number on the error message indicate the line of the
DECL, use cp_error_at
and its ilk; to indicate which argument you want,
use %+D
, or it will default to the first.
Some comments on the parser:
The after_type_declarator
/ notype_declarator
hack is
necessary in order to allow redeclarations of TYPENAME
s, for
instance
typedef int foo; class A { char *foo; };
In the above, the first foo
is parsed as a notype_declarator
,
and the second as a after_type_declarator
.
Ambiguities:
There are currently four reduce/reduce ambiguities in the parser. They are:
1) Between template_parm
and
named_class_head_sans_basetype
, for the tokens aggr
identifier
. This situation occurs in code looking like
template <class T> class A { };
It is ambiguous whether class T
should be parsed as the
declaration of a template type parameter named T
or an unnamed
constant parameter of type class T
. Section 14.6, paragraph 3 of
the January '94 working paper states that the first interpretation is
the correct one. This ambiguity results in two reduce/reduce conflicts.
2) Between primary
and type_id
for code like `int()'
in places where both can be accepted, such as the argument to
sizeof
. Section 8.1 of the pre-San Diego working paper specifies
that these ambiguous constructs will be interpreted as typename
s.
This ambiguity results in six reduce/reduce conflicts between
`absdcl' and `functional_cast'.
3) Between functional_cast
and
complex_direct_notype_declarator
, for various token strings.
This situation occurs in code looking like
int (*a);
This code is ambiguous; it could be a declaration of the variable `a' as a pointer to `int', or it could be a functional cast of `*a' to `int'. Section 6.8 specifies that the former interpretation is correct. This ambiguity results in 7 reduce/reduce conflicts. Another aspect of this ambiguity is code like 'int (x[2]);', which is resolved at the '[' and accounts for 6 reduce/reduce conflicts between `direct_notype_declarator' and `primary'/`overqualified_id'. Finally, there are 4 r/r conflicts between `expr_or_declarator' and `primary' over code like 'int (a);', which could probably be resolved but would also probably be more trouble than it's worth. In all, this situation accounts for 17 conflicts. Ack!
The second case above is responsible for the failure to parse 'LinppFile ppfile (String (argv[1]), &outs, argc, argv);' (from Rogue Wave Math.h++) as an object declaration, and must be fixed so that it does not resolve until later.
4) Indirectly between after_type_declarator
and parm
, for
type names. This occurs in (as one example) code like
typedef int foo, bar; class A { foo (bar); };
What is bar
inside the class definition? We currently interpret
it as a parm
, as does Cfront, but IBM xlC interprets it as an
after_type_declarator
. I believe that xlC is correct, in light
of 7.1p2, which says "The longest sequence of decl-specifiers that
could possibly be a type name is taken as the decl-specifier-seq of
a declaration." However, it seems clear that this rule must be
violated in the case of constructors. This ambiguity accounts for 8
conflicts.
Unlike the others, this ambiguity is not recognized by the Working Paper.
°ÑÀ¸·Î º¸±â¿¡´Â ÀϹÝÀûÀÎ Äڵ尡 syntax error at `\{'
¿Í °°Àº ¿À·ùµé·Î ½ÇÆÐÇÒ¶§¸¶´Ù, grokdeclarator´Â ÀÌÀ¯°¡ ¹«¾ùÀ̵çÁö ÀÌ¿¡ ´ëÇØ NULL_TREE¸¦ ¹ÝȯÇÏ´Â°Í °°´Ù.
It should never be that case that trees are modified in-place by the back-end, unless it is guaranteed that the semantics are the same no matter how shared the tree structure is. `fold-const.c' still has some cases where this is not true, but rms hypothesizes that this will never be a problem.
ÅÛÇø´Àº TEMPLATE_DECL
¿¡ ÀÇÇØ Ç¥ÇöµÈ´Ù. ƯÁ¤ Çʵ尡 »ç¿ëµÈ´Ù:
DECL_TEMPLATE_RESULT
DECL_TEMPLATE_PARMS
generic declÀº µÉ ¼ö ÀÖ´Â ´ë·Î ¸¹ÀÌ ´Ù¸¥ decló·³ ÆĽº(parse)µÈ´Ù. generic declÀº parameterizationÀÌ ÁÖ¾îÁø´Ù. ÅÛÇø´ declÀº generic declÀÌ ¿Ï·áµÉ¶§±îÁö ¸¸µé¾î ÁöÁö ¾Ê´Â´Ù. ÅÛÇø´ Ŭ·¡½º¿¡ ´ëÇÑ ÅÛÇø´ declÀº °Ô´Ù°¡ °¢ ¸â¹ö ÇÔ¼ö¿Í Á¤Àû µ¥ÀÌŸ ¸â¹ö¿¡ ´ëÇØ »ý¼ºµÈ´Ù.
ÅÛÇø´ Ŭ·¡½ºÀÇ ÅÛÇø´ ¸â¹ö´Â ¸â¹öÀÇ ¸Å°³º¯¼ö¿¡ ´ëÇÑ ´Ù¸¥ TEMPLATE_DECL ÁÖº¯ÀÇ Å¬·¡½º ¸Å°³º¯¼ö¿¡ ´ëÇØ TEMPLATE_DECL¿¡ ÀÇÇØ Ç¥ÇöµÈ´Ù.
ÅÛÇø´ÀÇ instantiation À̳ª specialization ÀÎ ¸ðµç ¼±¾ðÀº DECL_TEMPLATE_INFO¸¦ ÅëÇØ ±×µéÀÇ ÅÛÇø´°ú ¸Å°³º¯¼ö·Î ¾ð±ÞµÈ´Ù.
¾î¶»°Ô ÀûÀýÇÑ param declÀ» °¡Áø parsing member funcionÀ» Ãë±ÞÇؾßÇϴ°¡? ±×°ÍµéÀ» ´Ù½Ã ¼³Á¤Çϰųª °°Àº °ÍµéÀ» »ç¿ëÇϵµ·Ï ½ÃµµÇضó? ÇöÀç ¿ì¸®´Â ÀüÀÚ¸¦ ÇàÇÑ´Ù. do_pending_inline¾È¿¡ decl·ÎºÎÅÍ ¿Â ¸Å°³º¯¼ö¸¦ Á¦°ÅÇÔÀ¸·Î½á, store_pending_inline¿¡ ¾î¶°ÇÑ ¿©ºÐÀÇ ±â°è¾øÀÌ ¾Æ¸¶ ÀÌ°ÍÀ» ÇÒ ¼ö ÀÖ´Ù. PRE_PARSED_TEMPLATE_DECL?
¸¸¾à base°¡ parmÀ̶ó¸é, ±×¿¡ ´ëÇÑ ¾î¶°ÇÑ °Íµµ °Ë»çÇÒ ¼ö ¾ø´Ù. ¸¸¾à base°¡ parmÀÌ ¾Æ´Ï¶ó¸é, name binding¿¡ ´ëÇØ ±×°ÍÀ» °Ë»çÇÒ ÇÊ¿ä°¡ ÀÖ´Ù. ¸¸¾à ¾î¶°ÇÑ baseµµ parameterizedÇÏÁö ¾Ê´Ù¸é(only if none,including indirect,are params) finish_base_struct¸¦ ÇàÇ϶ó. ¾Æ´Ï, ¼³Ä¡±îÁö À̵éÁß ¾î¶² °ÍÀ» Çغ¼·Á°í ½ÃµµÇؼ ±«·ÓÈ÷Áö ¸»¶ó--¿ì¸®´Â ´ÜÁö ¹Ì¸® name bindingÀ» ÇàÇÏ´Â °ÍÀÌ ÇÊ¿äÇÏ´Ù.
Always set up method vec and fields, inc. synthesized mthods. Á¤¸»? ¿ì¸®´Â base¿Í field¸¦ ¾Ë¶§±îÁö, copy folkÀÇ ÇüÀ» ¾Ë ¼ö ¾ø°Å³ª ¶Ç´Â ¿ì¸®°¡ ¼Ò¸êÀÚ¸¦ ÇÊ¿ä·Î ÇÑÁö¸¦, ¶Ç´Â µðÆúÆ® ctor¸¦ °¡Áú ¼ö ÀÖ´ÂÁö¸¦ ¾Ë ¼ö ¾ø´Ù. ±×·¸Áö ¾ÊÀ¸¸é ÈÄ¿¡ ÀÚ½ÅÀÌ Á÷Á¢ °íÄ¥ ¼ö ÀÖ´Ù. À߸¸µÇ¸é..
ÇÔ¼ö compute_access´Â ´ÙÀ½ ¼¼°¡Áö °ªÁß Çϳª¸¦ ¹ÝȯÇÑ´Ù:
access_public
access_protected
access_private
DECL_ACCESS´Â Á¢¼Ó ¼±¾ðÀ» À§ÇØ »ç¿ëµÈ´Ù: alter_access´Â ÇüÀÇ ¸ñ·Ï°ú ÁÖ¾îÁø decl¿¡ ´ëÇÑ Á¢¼ÓÀ» »ý¼ºÇÑ´Ù.
Àü¿¡, DECL_{PUBLIC, PROTECTED,PRIVATE} Àº compute_accessÀÇ ¹Ýȯ Äڵ忡 ´ëÀÀÇß°í compute_access¸¦ À§ÇÑ Ä³½¬(cache)·Î½á »ç¿ëµÇ¾ú´Ù. ÀÌÁ¦ ±×°ÍµéÀº ÀüÇô »ç¿ëµÇÁö ¾Ê´Â´Ù.
TREE_PROTECTED, TREE_PRIVATE´Â containing class¿¡ ÀÇÇØ Çã¿ëµÈ Á¢¼Ó ¼öÁØ(level)À» ±â·ÏÇϴµ¥ »ç¿ëµÈ´Ù. Á¶½É: TREE_PUBLICÀº Á¢¼Ó Á¦¾î¿Í ¿ÏÀüÈ÷ °ü°è¾ø´Â ¾î¶²°ÍÀ» ÀǹÌÇÑ´Ù!
C++ front-end´Â Çü¿¡ ´ëÇÑ Àû´çÇÑ ¹®ÀÚ¿À» ÇÁ¸°Æ®ÇÏ´Â ÇÔ¼ö¿Í ¿À·ù°¡ ¹ß°ßµÈ ÇÔ¼ö¿¡ ¿©ºÐÀÇ ·ÎÁ÷À» Áý¾î³ÖÁö ¾Ê´Â ÇÔ¼ö¸¦ Çã°¡ÇÏ´Â Äݹé(call-back) ¸ÞÄ¿´ÏÁòÀ» »ç¿ëÇÑ´Ù.
ÀÎÅÍÆäÀ̽º´Â cp_error
ÇÔ¼ö¸¦ ÅëÇؼ µÈ´Ù (¶Ç´Â cp_warning
, µî). ¹®¹ýÀº ¸î°¡Áö º¯È¯ÀÌ Áö¿øµÈ´Ù´Â Á¡À» Á¦¿ÜÇÏ°í´Â error
¿Í Á¤È®È÷ °°´Ù:
ÀÌµé »çÀÌ¿¡ ¸î°¡Áö Áߺ¹µÇ´Â°ÍÀÌ ÀÖ´Ù: ¿¹·Î½á ³ëµå ¿É¼ÇÁß ¾î¶² °ÍÀÌµç ½Äº°ÀÚ¸¦ ÇÁ¸°Æ®ÇϱâÀ§ÇØ »ç¿ëµÉ ¼ö ÀÖ´Ù(ºñ·Ï %D
¸¸Àº ÇÔ¼ö¸íÀ» ¹ø¿ªÇÏ·Á°í ½ÃµµÇÒÁö¶óµµ).
´õ ¸¹Àº verbose message¿¡ ´ëÇØ(´Ü¼øÇÑ foo
¿¡ ´ë¸³ÇÏ´Â °ÍÀ¸·Î¼ Ŭ·¡½º foo
, ÇÔ¼ö¿¡ ´ëÇÑ ¹Ýȯ ÇüÀ» Æ÷ÇÔÇÏ´Â), %#c
¸¦ »ç¿ëÇ϶ó.
¿À·ù ¸Þ½ÃÁö»ó¿¡ ¶óÀÎ ¼ö¸¦ °¡Áö´Â °ÍÀº DECLÀÇ ¶óÀÎÀ» °¡¸£Å²´Ù. cp_error_at
¿Í ±×°ÍÀÇ µ¿·ù(ÔÒ×¾;ilk)¸¦ »ç¿ëÇ϶ó;
¿øÇÏ´Â ÀÎÀÚ¸¦ Áö½ÃÇϱâÀ§ÇØ %+D
¸¦ »ç¿ëÇ϶ó. ¶Ç´Â ±×°ÍÀº ¿ì¼± µðÆúÆ®ÀÏ °ÍÀÌ´Ù.
Æļ(Parser)¿¡ °üÇÑ ¸î°¡Áö ¼³¸í:
after_type_declarator
/ notype_declarator
hack´Â TYPENAME
ÀÇ Àç¼±¾ðÀ» Çã¿ëÇϱâÀ§ÇØ ÇÊ¿äÇÏ´Ù. ¿¹¸¦ µé¸é,
typedef int foo; class A { char *foo; };
À§¿¡¼ ù¹ø° foo
´Â notype_declarator
·Î½á ÆĽºµÈ´Ù. ±×¸®°í µÎ¹ø°°ÍÀº after_type_declarator
·Î½á ÆĽºµÈ´Ù.
¸ðÈ£¼º(Ambiguity):
ÀϹÝÀûÀ¸·Î Æļ¿¡ 4°³ÀÇ reduce/reduce ¸ðÈ£¼ºÀÌ ÀÖ´Ù. ±×°ÍµéÀº ´ÙÀ½°ú °°´Ù:
1) tokens aggr identifier
¸¦ À§ÇÑ template_parm
°ú named_class_head_sans_basetype
»çÀÌ.
ÀÌ·¯ÇÑ »óȲÀº ´ÙÀ½°ú °°Àº Äڵ忡¼ ¹ß»ýÇÑ´Ù.
template <class T> class A { };
class T
°¡ T
¶ó´Â À̸§À» °¡Áø ÅÛÇø´Çü ¸Å°³º¯¼öÀÇ ¼±¾ð·Î½á ÆĽºµÇ¾ßµÉÁö, ¶Ç´Â class T
ÇüÀÇ À̸§ÀÌ ¾ø´Â »ó¼ö ¸Å°³º¯¼ö·Î½á ÆĽºµÇ¾ßµÉÁö°¡ ¾Ö¸Å¸ðÈ£ÇÏ´Ù.
14.6Àý, '94³â 1¿ù working paperÀÇ 3Ç×(paragraph)Àº ÃÖÃÊÀÇ Çؼ®ÀÌ ¿Ç´Ù°í ¼³¸íÇÑ´Ù. ÀÌ°ÍÀº ¸ðÈ£¼ºÀÌ 2 reduce/reduce Ãæµ¹À» °á°úÇÑ´Ù.
2) µÑ´Ù Çã¿ëµÉ ¼ö ÀÖ´Â °÷¿¡ ÀÖ´Â `int()' °°Àº Äڵ忡 ´ëÇÑ primary
¿Í type_id
»çÀÌ. À̸¦ Å׸é sizeof
¿¡ ´ëÇÑ ÀÎÀÚ.
pre-San Diego working paperÀÇ 8.1ÀýÀº ÀÌ·¯ÇÑ ¾Ö¹Ì¸ðÈ£ÇÑ ±¸¼ºÀÌ typename
·Î½á Çؼ®µÉ °ÍÀ̶ó´Â °ÍÀ» ¸í±âÇÑ´Ù.
ÀÌ·¯ÇÑ ¸ðÈ£¼ºÀº `absdcl'°ú `functional_cast'»çÀÌÀÇ 6 reduce/reduce Ãæµ¹À» °á°úÇÑ´Ù.
3) ´Ù¾çÇÑ token stringÀ» À§ÇÑ functional_cast
¿Í complex_direct_notype_declarator
»çÀÌ. ÀÌ·¯ÇÑ »óȲÀº ´ÙÀ½°ú °°Àº Äڵ忡 ¹ß»ýÇÑ´Ù.
int (*a);
ÀÌ ÄÚµå´Â ¾Ö¸Å¸ðÈ£ÇÏ´Ù: ±×°ÍÀº `int'¿¡ ´ëÇÑ Æ÷ÀÎÅä·Î½á º¯¼ö `a'ÀÇ ¼±¾ðÀÌ µÉ ¼ö Àְųª `int' ¿¡ ´ëÇÑ `*a'ÀÇ functional case°¡ µÉ ¼ö ÀÖ´Ù. 6.8ÀýÀº ÀÌÀüÀÇ Çؼ®ÀÌ ¿Ç´Ù´Â °ÍÀ» ¸í±âÇÑ´Ù. ÀÌ ¸ðÈ£¼ºÀº 7 reduce/reduce Ãæµ¹À» °á°úÇÑ´Ù. ÀÌ·¯ÇÑ ¸ðÈ£¼ºÀÇ ´Ù¸¥ ¾ç»óÀº 'int (x[2]);' °°Àº ÄÚµåÀÌ´Ù. ±×¸®°í ±×°ÍÀº '['¿¡¼ Çؼ®µÇ°í `direct_notype_declarator'°ú `primary'/`overqualified_id' »çÀÌÀÇ 6 reduce/reduce Ãæµ¹¿¡ ´ëÇÑ ¿øÀÎÀÌ µÈ´Ù. °á±¹, 'int (a);'°°Àº Äڵ忡 ´ëÇÑ `expr_or_declarator'°ú `primary'»çÀÌÀÇ 4 r/r Ãæµ¹ÀÌ ÀÖ´Ù. ±×¸®°í ±×°ÍÀº Çؼ®ÀÌ µÉÁöµµ ¸ð¸£³ª ¶ÇÇÑ ±×°ÍÀÇ °¡Ä¡º¸´Ù ´õ ¸¹Àº ¹®Á¦°¡ µÉÁöµµ ¸ð¸¥´Ù. ÀüºÎÇؼ ÀÌ·¯ÇÑ »óȲÀº 17 Ãæµ¹¿¡ ´ëÇÑ ¿øÀÎÀÌ µÈ´Ù. Ack!
À§ µÎ¹ø° °æ¿ì´Â °´Ã¼ ¼±¾ðÀ¸·Î LinppFile ppfile (String (argv[1]), &outs, argc, argv);' (from Rogue Wave Math.h++)¸¦ ÆĽºÇÏ´Â ½ÇÆи¦ ÃÊ·¡ÇÑ´Ù. ±×¸®°í ÀÌÈÄ¿¡±îÁö Çؼ®µÇÁö ¾Êµµ·Ï °íÃÄÁ®¾ß ÇÑ´Ù.
4) °£Á¢ÀûÀ¸·Î after_type_declarator
°ú parm
»çÀÌ. ÀÌ°ÍÀº ´ÙÀ½°ú °°Àº Äڵ忡¼(ÇÑ ¿¹·Î½á) ¹ß»ýÇÑ´Ù.
typedef int foo, bar; class A { foo (bar); };
Ŭ·¡½º Á¤Àdz»¿¡ bar
´Â ¹«¾ùÀΰ¡? ¿ì¸®´Â Áö±Ý Cfront¸¦ ÇàÇÏ´Â °Íó·³ ±×°ÍÀ» parm
·Î½á Çؼ®ÇÑ´Ù.
±×·¯³ª IBM xIC´Â after_type_declarator
·Î½á ±×°ÍÀ» Çؼ®ÇÑ´Ù.
"Çü¸í(type name)ÀÌ µÉ ¼ö decl-specifiersÀÇ °¡Àå ±ä ¿Àº ¼±¾ðÀÇ decl-specifier-seq ·Î½á ÃëµæµÈ´Ù."¶ó°í ¸»ÇÑ 7.1p2·Î ¹Ì·ç¾î º¸¾Æ ³ª´Â xIC°¡ ¿Ç´Ù°í ¹Ï´Â´Ù.
±×·¯³ª ÀÌ ±ÔÄ¢Àº »ý¼ºÀÚÀÇ °æ¿ì¿¡ À§¹ÝµÊÀÌ Æ²¸²¾ø´Ù´Â °ÍÀÌ ºÐ¸íÇÑ °Í °°´Ù. ÀÌ ¸ðÈ£¼ºÀº 8 Ãæµ¹¿¡ ´ëÇÑ ¿øÀÎÀÌ µÈ´Ù.
´Ù¸¥ °Í°ú ´Þ¸®, ÀÌ ¸ðÈ£¼ºÀº Working Paper¿¡ ÀÇÇØ ÀνĵÇÁö ¾Ê´Â´Ù.
Note, exception handling in g++ is still under development.
This section describes the mapping of C++ exceptions in the C++ front-end, into the back-end exception handling framework.
The basic mechanism of exception handling in the back-end is unwind-protect a la elisp. This is a general, robust, and language independent representation for exceptions.
The C++ front-end exceptions are mapping into the unwind-protect semantics by the C++ front-end. The mapping is describe below.
When -frtti is used, rtti is used to do exception object type checking, when it isn't used, the encoded name for the type of the object being thrown is used instead. All code that originates exceptions, even code that throws exceptions as a side effect, like dynamic casting, and all code that catches exceptions must be compiled with either -frtti, or -fno-rtti. It is not possible to mix rtti base exception handling objects with code that doesn't use rtti. The exceptions to this, are code that doesn't catch or throw exceptions, catch (...), and code that just rethrows an exception.
Currently we use the normal mangling used in building functions names (int's are "i", const char * is PCc) to build the non-rtti base type descriptors for exception handling. These descriptors are just plain NULL terminated strings, and internally they are passed around as char *.
In C++, all cleanups should be protected by exception regions. The region starts just after the reason why the cleanup is created has ended. For example, with an automatic variable, that has a constructor, it would be right after the constructor is run. The region ends just before the finalization is expanded. Since the backend may expand the cleanup multiple times along different paths, once for normal end of the region, once for non-local gotos, once for returns, etc, the backend must take special care to protect the finalization expansion, if the expansion is for any other reason than normal region end, and it is `inline' (it is inside the exception region). The backend can either choose to move them out of line, or it can created an exception region over the finalization to protect it, and in the handler associated with it, it would not run the finalization as it otherwise would have, but rather just rethrow to the outer handler, careful to skip the normal handler for the original region.
In Ada, they will use the more runtime intensive approach of having fewer regions, but at the cost of additional work at run time, to keep a list of things that need cleanups. When a variable has finished construction, they add the cleanup to the list, when the come to the end of the lifetime of the variable, the run the list down. If the take a hit before the section finishes normally, they examine the list for actions to perform. I hope they add this logic into the back-end, as it would be nice to get that alternative approach in C++.
On an rs6000, xlC stores exception objects on that stack, under the try block. When is unwinds down into a handler, the frame pointer is adjusted back to the normal value for the frame in which the handler resides, and the stack pointer is left unchanged from the time at which the object was thrown. This is so that there is always someplace for the exception object, and nothing can overwrite it, once we start throwing. The only bad part, is that the stack remains large.
The below points out some things that work in g++'s exception handling.
All completely constructed temps and local variables are cleaned up in all unwinded scopes. Completely constructed parts of partially constructed objects are cleaned up. This includes partially built arrays. Exception specifications are now handled. Thrown objects are now cleaned up all the time. We can now tell if we have an active exception being thrown or not (__eh_type != 0). We use this to call terminate if someone does a throw; without there being an active exception object. uncaught_exception () works. Exception handling should work right if you optimize. Exception handling should work with -fpic or -fPIC.
The below points out some flaws in g++'s exception handling, as it now stands.
Only exact type matching or reference matching of throw types works when -fno-rtti is used. Only works on a SPARC (like Suns) (both -mflat and -mno-flat models work), SPARClite, Hitachi SH, i386, arm, rs6000, PowerPC, Alpha, mips, VAX, m68k and z8k machines. SPARC v9 may not work. HPPA is mostly done, but throwing between a shared library and user code doesn't yet work. Some targets have support for data-driven unwinding. Partial support is in for all other machines, but a stack unwinder called __unwind_function has to be written, and added to libgcc2 for them. The new EH code doesn't rely upon the __unwind_function for C++ code, instead it creates per function unwinders right inside the function, unfortunately, on many platforms the definition of RETURN_ADDR_RTX in the tm.h file for the machine port is wrong. See below for details on __unwind_function. RTL_EXPRs for EH cond variables for && and || exprs should probably be wrapped in UNSAVE_EXPRs, and RTL_EXPRs tweaked so that they can be unsaved.
We only do pointer conversions on exception matching a la 15.3 p2 case 3: `A handler with type T, const T, T&, or const T& is a match for a throw-expression with an object of type E if [3]T is a pointer type and E is a pointer type that can be converted to T by a standard pointer conversion (_conv.ptr_) not involving conversions to pointers to private or protected base classes.' when -frtti is given.
We don't call delete on new expressions that die because the ctor threw an exception. See except/18 for a test case.
15.2 para 13: The exception being handled should be rethrown if control reaches the end of a handler of the function-try-block of a constructor or destructor, right now, it is not.
15.2 para 12: If a return statement appears in a handler of function-try-block of a constructor, the program is ill-formed, but this isn't diagnosed.
15.2 para 11: If the handlers of a function-try-block contain a jump into the body of a constructor or destructor, the program is ill-formed, but this isn't diagnosed.
15.2 para 9: Check that the fully constructed base classes and members of an object are destroyed before entering the handler of a function-try-block of a constructor or destructor for that object.
build_exception_variant should sort the incoming list, so that it implements set compares, not exact list equality. Type smashing should smash exception specifications using set union.
Thrown objects are usually allocated on the heap, in the usual way. If one runs out of heap space, throwing an object will probably never work. This could be relaxed some by passing an __in_chrg parameter to track who has control over the exception object. Thrown objects are not allocated on the heap when they are pointer to object types. We should extend it so that all small (<4*sizeof(void*)) objects are stored directly, instead of allocated on the heap.
When the backend returns a value, it can create new exception regions that need protecting. The new region should rethrow the object in context of the last associated cleanup that ran to completion.
The structure of the code that is generated for C++ exception handling code is shown below:
Ln: throw value; copy value onto heap jump throw (Ln, id, address of copy of value on heap) try { +Lstart: the start of the main EH region |... ... +Lend: the end of the main EH region } catch (T o) { ...1 } Lresume: nop used to make sure there is something before the next region ends, if there is one ... ... jump Ldone [ Lmainhandler: handler for the region Lstart-Lend cleanup ] zero or more, depending upon automatic vars with dtors +Lpartial: | jump Lover +Lhere: rethrow (Lhere, same id, same obj); Lterm: handler for the region Lpartial-Lhere call terminate Lover: [ [ call throw_type_match if (eq) { ] these lines disappear when there is no catch condition +Lsregion2: | ...1 | jump Lresume |Lhandler: handler for the region Lsregion2-Leregion2 | rethrow (Lresume, same id, same obj); +Leregion2 } ] there are zero or more of these sections, depending upon how many catch clauses there are ----------------------------- expand_end_all_catch -------------------------- here we have fallen off the end of all catch clauses, so we rethrow to outer rethrow (Lresume, same id, same obj); ----------------------------- expand_end_all_catch -------------------------- [ L1: maybe throw routine ] depending upon if we have expanded it or not Ldone: ret start_all_catch emits labels: Lresume,
The __unwind_function takes a pointer to the throw handler, and is expected to pop the stack frame that was built to call it, as well as the frame underneath and then jump to the throw handler. It must restore all registers to their proper values as well as all other machine state as determined by the context in which we are unwinding into. The way I normally start is to compile:
void *g; foo(void* a) { g = a; }
with -S, and change the thing that alters the PC (return, or ret usually) to not alter the PC, making sure to leave all other semantics (like adjusting the stack pointer, or frame pointers) in. After that, replicate the prologue once more at the end, again, changing the PC altering instructions, and finally, at the very end, jump to `g'.
It takes about a week to write this routine, if someone wants to volunteer to write this routine for any architecture, exception support for that architecture will be added to g++. Please send in those code donations. One other thing that needs to be done, is to double check that __builtin_return_address (0) works.
g++¿¡¼ ¿¹¿Ü󸮴 ¾ÆÁ÷ °³¹ßÁßÀÓÀ» ÁÖÀÇÇ϶ó.
º» ÀýÀº back-end ¿¹¿Ü ó¸® ±¸Á¶¾ÈÀ¸·Î C++ front-end³» C++ ¿¹¿ÜÀÇ ¸ÅÇÎ(mapping)À» ±â¼úÇÑ´Ù.
back-end³» ¿¹¿Ü ó¸®ÀÇ ±âº» ¸ÞÄ¿´ÏÁòÀº unwind-protect a la elispÀÌ´Ù. ÀÌ°ÍÀº ¿¹¿Ü¿¡ ´ëÇÑ ÀϹÝÀûÀÌ°í Æ°Æ°ÇÏ°í ¾ð¾î µ¶¸³ÀûÀΠǥÇöÀÌ´Ù.
C++ front-end ¿¹¿Ü´Â C++ front-end¿¡ ÀÇÇØ unwind-protect Àǹ̷Ð(semantics)¾ÈÀ¸·Î ¸ÅÇεȴÙ. ¸ÅÇÎÀº ¾Æ·¡¿¡ ±â¼úµÈ´Ù.
-frtti °¡ »ç¿ëµÉ ¶§, rtti´Â ¿¹¿Ü °´Ã¼ Çü °Ë»ç(exception object type checking)¸¦ ÇàÇϴµ¥ »ç¿ëµÈ´Ù. ±×°ÍÀÌ »ç¿ëµÇÁö ¾ÊÀ»¶§, ½º·Î¿ì(throw)µÈ °´Ã¼ÀÇ Çü¿¡ ´ëÇÑ ÄÚµåÈµÈ À̸§ÀÌ ´ë½Å »ç¿ëµÈ´Ù. ¿¹¿Ü¸¦ ÀÏÀ¸Å² ¸ðµç ÄÚµå, µ¿Àû ij½ºÆÃ(dynamic casting)ó·³ ½ÉÁö¾î ºÎ°¡ÀûÀÎ È¿°ú·Î ¿¹¿Ü¸¦ ½º·Î¿ì(throw) ÇÑ ÄÚµå, ±×¸®°í ¿¹¿Ü¸¦ ijġ(catch)ÇÑ ¸ðµç ÄÚµå´Â -frtti³ª -fno-rtti¸¦ °¡Áö°í ÄÄÆÄÀϵǾî¾ß ÇÑ´Ù. rtti base ¿¹¿Ü ó¸® °´Ã¼¸¦ rtti¸¦ »ç¿ëÇÏÁö ¾Ê´Â ÄÚµå¿Í ÇÔ²² ¼¯¾î¼ »ç¿ëÇÏ´Â °ÍÀº ºÒ°¡´ÉÇÏ´Ù. ÀÌ°Í¿¡ ´ëÇÑ ¿¹¿Ü´Â ¿¹¿Ü¸¦ ijġÇϰųª ½º·Î¿ìÇÏÁö ¾Ê´Â ÄÚµå, catch (...), ¿¹¿Ü¸¦ ´Ù½Ã ½º·Î¿ì¸¸ÇÏ´Â ÄÚµåÀÌ´Ù.
¿äÁòÀº ¿¹¿Ü󸮿¡ ´ëÇÑ non-rtti base type descriptor¸¦ ¸¸µé±âÀ§ÇÑ ÇÔ¼ö¸íÀ» ¸¸µå´Âµ¥ »ç¿ëµÈ normal manglingÀ» »ç¿ëÇÑ´Ù. ÀÌ descriptor´Â ´ÜÁö °£´ÜÇÑ NULL terminated string ÀÌ°í, ³»ºÎÀûÀ¸·Î ±×°ÍµéÀº char *·Î½á Â÷·Ê·Î µ¹·ÁÁø´Ù.
C++¿¡¼ ¸ðµç cleanupÀº ¿¹¿Ü ¿µ¿ª¿¡ ÀÇÇØ º¸È£µÇ¾ß ÇÑ´Ù. ¿µ¿ªÀº »ý¼ºµÈ cleanupÀÌ Á¾·áµÈ ÈÄ¿¡ ¹Ù·Î ½ÃÀÛÇÑ´Ù. ¿¹·Î½á »ý¼ºÀÚ¸¦ °¡Áø ÀÚµ¿ º¯¼ö¸¦ °¡Áö°í, ±×°ÍÀº »ý¼ºÀÚ°¡ µ¿ÀÛÇÑ ÈÄ Á¤»óÀÌ µÉ °ÍÀÌ´Ù. ¿µ¿ªÀº finalizationÀÌ È®ÀåµÇ±â ¹Ù·ÎÀü¿¡ ³¡³´Ù. backend°¡ ´Ù¸¥ °æ·Î(¿µ¿ªÀÇ normal end¿¡ ´ëÇØ Çѹø, non-local goto¿¡ ´ëÇØ Çѹø, ¹Ýȯ¿¡ ´ëÇØ Çѹø, ±âŸ)¸¦ µû¶ó cleanup multiple times¸¦ È®Àå½ÃųÁöµµ ¸ð¸£±â ¶§¹®¿¡, backend´Â finalization È®ÀåÀ» ¸·´Âµ¥ Ưº°ÇÑ ÁÖÀǸ¦ °¡Á®¾ß ÇÑ´Ù. ¸¸¾à È®ÀåÀÌ normal region endº¸´Ù Å©´Ù´Â ÀÌÀ¯°¡ ¾Æ´Ñ ´Ù¸¥ ÀÌÀ¯¶ó¸é, ±×°ÍÀº 'inline'ÀÌ´Ù(±×°ÍÀº ¿¹¿Ü ¿µ¿ª¾ÈÂÊÀÌ´Ù). backend´Â ¶óÀÎÀÇ ¹ÛÀ¸·Î ±×°ÍµéÀ» À̵¿½Ãų ¼ö Àְųª, ±×°ÍÀ» º¸È£ÇÏ´Â finalization¿¡ °üÇÑ ¿¹¿Ü ¿µ¿ªÀ» »ý¼ºÇÒ ¼ö ÀÖ°í, ±×°Í°ú ¿¬°üµÈ Çڵ鷯(handler) ³»¿¡ ¿¹¿Ü ¿µ¿ªÀ» »ý¼ºÇÒ ¼ö ÀÖ´Ù. ±×°ÍÀº ±×°ÍÀÌ °¡Áö°í ÀÖ´Â °Í°ú ´Þ¸® finalizationÀ» µ¿ÀÛ½ÃÅ°´Â °ÍÀÌ ¾Æ´Ï¶ó ¿ÀÈ÷·Á ¿ø·¡ ¿µ¿ª¿¡ ´ëÇÑ normal Çڵ鷯¸¦ °Ç³Ê¶Ù´Â °Í¿¡ ÁÖÀÇÇÏ¿© ¿Ü°ûÀÇ Çڵ鷯¿¡°Ô Àç ½º·Î¿ìÇÑ´Ù.
Ada¿¡¼ ±×°ÍµéÀº ´õ ÀûÀº ¿µ¿ªÀ» °¡Áø Á»´õ runtime Áý¾àÀûÀÎ Á¢±ÙÀ» ÀÌ¿ëÇÒ °ÍÀÌ´Ù. ±×·¯³ª ½ÇÇà ½Ã°£¿¡ ºÎ°¡ÀûÀÎ ÀÛ¾÷ÀÇ ºñ¿ë¸é¿¡¼ cleanupÀ» ÇÊ¿ä·ÎÇÏ´Â °ÍµéÀÇ ¸ñ·ÏÀ» À¯ÁöÇÒ °ÍÀÌ´Ù. º¯¼ö°¡ ±¸¼ºÀ» ³¡³ÂÀ» ¶§, ±×°ÍµéÀº ¸ñ·ÏÀº cleanupÀ» Ãß°¡ÇÑ´Ù. º¯¼öÀÇ ¼ö¸íÀÌ ´ÙÇßÀ»¶§, ¸ñ·ÏÀ» Äf¾îº»´Ù. ¸¸¾à Àý(section)ÀÌ Á¤»óÀûÀ¸·Î ³¡³ª±â Àü¿¡ ã´Â´Ù¸é, ±×°ÍµéÀº ¼öÇàÇÑ ÇàÀ§¸¦ À§ÇØ ¸ñ·ÏÀ» Á¶»çÇÑ´Ù. ³ª´Â ±×µéÀÌ back-end³»¿¡ ÀÌ ·ÎÁ÷À» Ãß°¡Çϱ⸦ Èñ¸ÁÇÑ´Ù. C++¿¡¼ ´Ù¸¥ Á¢±Ù¹ýÀ» ¾ò±â¿¡ ÁÁÀ» °ÍÀÌ´Ù.
rs6000¿¡¼, xIC´Â try ºí·ÏÀÌÇÏ ±× ½ºÅÃ»ó¿¡ ¿¹¿Ü °´Ã¼¸¦ ÀúÀåÇÑ´Ù. Çڵ鷯 ¾È¿¡¼ Ç®·Á ³»·Á°¥¶§, ÇÁ·¹ÀÓ Æ÷ÀÎÅÍ´Â Çڵ鷯°¡ Á¸ÀçÇÏ´Â ÇÁ·¹ÀÓ¿¡ ´ëÇÑ Á¤»ó°ªÀ¸·Î Á¶Á¤µÈ´Ù. ±×¸®°í ½ºÅÃÆ÷ÀÎÅÍ´Â °´Ã¼°¡ ½º·Î¿ìµÈ ½Ã°£ºÎÅÍ º¯°æµÇÁö ¾ÊÀºÃ¤·Î ³õ¾ÆµÐ´Ù. ÀÌ°ÍÀº ¿¹¿Ü °´Ã¼¸¦ À§ÇÑ ¾î¶² Àå¼Ò°¡ Ç×»ó Á¸ÀçÇÑ´Ù´Â °ÍÀÌ´Ù. ±×¸®°í ¸¸¾à ½º·Î¿ì¸¦ ½ÃÀÛÇÑ´Ù¸é ¾î¶² °Íµµ ±×°ÍÀ» µ¤¾î¾µ ¼ö ¾ø´Ù. À¯ÀÏÇÑ °áÁ¡Àº ½ºÅÃÀÌ Å«Ã¤·Î ÀÖ´Ù´Â °ÍÀÌ´Ù.
¾Æ·¡´Â g++ÀÇ ¿¹¿Ü 󸮿¡¼ µ¿ÀÛÇÏ´Â ¸î°¡Áö °ÍµéÀ» ÁöÀûÇÑ´Ù.
¸ðµç ¿ÏÀüÈ÷ ±¸¼ºµÈ temp¿Í Áö¿ª º¯¼ö´Â ¸ðµç unwinded ¹üÀ§¿¡¼ Á¦°ÅµÈ´Ù. ºÎºÐÀûÀ¸·Î ±¸¼ºµÈ °´Ã¼ÀÇ ¿ÏÀüÈ÷ ±¸¼ºµÈ ºÎºÐÀº Á¦°ÅµÈ´Ù. ÀÌ°ÍÀº ºÎºÐÀûÀ¸·Î ¸¸µé¾îÁø ¹è¿À» Æ÷ÇÔÇÑ´Ù. ¿¹¿Ü ±ÔÁ¤(exception specification)Àº ÀÌÁ¦ 󸮵ȴÙ. ½º·Î¿ìµÈ °´Ã¼´Â ÀÌÁ¦ Ç×»ó Á¦°ÅµÈ´Ù. ¿ì¸®´Â ÀÌÁ¦ ½º·Î¿îµÈ È°¼º ¿¹¿Ü(active exception)¸¦ °¡Áö°í ÀÖ´Â ¾Æ´ÑÁö(__eh_type != 0)¸¦ ¸»ÇÒ ¼ö ÀÖ´Ù. ¸¸¾à ´©±º°¡°¡ ½º·Î¿ì¸¦ ÇàÇß´Ù¸é, terminate¸¦ È£ÃâÇϴµ¥ ÀÌ°ÍÀ» »ç¿ëÇÒ ¼ö ÀÖ´Ù; È°¼ºÈµÈ ¿¹¿Ü °´Ã¼¾øÀÌ uncauht_exception ()´Â µ¿ÀÛÇÑ´Ù. ¸¸¾à ÃÖÀûÈÇÑ´Ù¸é ¿¹¿Ü 󸮴 Á¦´ë·Î µ¿ÀÛÇØ¾ß ÇÑ´Ù. ¿¹¿Ü 󸮴 -fpic ¶Ç´Â -fPIC¸¦ °¡Áö°í µ¿ÀÛÇØ¾ß ÇÑ´Ù.
¾Æ·¡´Â g++ÀÇ ¿¹¿Ü 󸮿¡¼ ¸î°¡Áö °áÁ¡À» ÁöÀûÇÑ´Ù. ±×°ÍÀº ÇöÀç Á¸ÀçÇÑ´Ù.
½º·Î¿ì ÇüÀÇ Á¤È®ÇÑ Çü ¸ÅĪ(type matching)À̳ª ÂüÁ¶ ¸ÅĪ(reference matching)¸¸ÀÌ -fno-rtti°¡ »ç¿ëµÉ ¶§ µ¿ÀÛÇÑ´Ù. SPARC(Suns¿Í °°Àº)(-mflat¿Í -mno-flat ¸ðµ¨¸ðµÎ µ¿ÀÛÇÑ´Ù), SPARClite, Hitachi SH, i386, arm, rs6000, PowerPC, Alpha, mips, VAX, m68k, z8k ±â°è¿¡¼¸¸ µ¿ÀÛÇÑ´Ù. SPARC v9´Â µ¿ÀÛ ¾ÈÇÒÁöµµ ¸ð¸¥´Ù. HPPA´Â °ÅÀÇ µÈ´Ù. ±×·¯³ª °øÀ¯ ¶óÀ̺귯¸®¿Í »ç¿ëÀÚ ÄÚµå»çÀÌ¿¡¼ ½º·Î¿ìÇϴ°ÍÀº ¾ÆÁ÷ µ¿ÀÛÇÏÁö ¾Ê´Â´Ù. ¸î¸î Ÿ°ÙÀº µ¥ÀÌŸ ±¸µ¿ unwinding¿¡ ´ëÇÑ Áö¿øÀ» °¡Áö°í ÀÖ´Ù. ºÎºÐÀûÀÎ Áö¿øÀº ¸ðµç ´Ù¸¥ ±â°è¿¡ ´ëÇØ ÀÖ´Ù. ±×·¯³ª __unwind_functionÀ̶ó ºÒ¸®´Â ½ºÅà unwinder´Â ½áÁ®¾ß ÇÑ´Ù. ±×¸®°í ±×°ÍµéÀ» À§ÇØ libgcc2¿¡ Ãß°¡µÇ¾îÁ®¾ß ÇÑ´Ù. »õ·Î¿î EH ÄÚµå´Â C++ Äڵ带 À§ÇÑ __unwind_function¿¡ ÀÇÁöÇÏÁö ¾Ê´Â´Ù. ±× ´ë½Å¿¡ ÇÔ¼ö ¹Ù·Î¾ÈÂÊ¿¡ °¢ function unwinder¸¦ »ý¼ºÇÑ´Ù. ºÒÇàÈ÷µµ ¸¹Àº Ç÷§Æû(platform)¿¡ ´ëÇØ ±â°è Æ÷Æ®(machine port)¸¦ À§ÇÑ tm.h ÆÄÀϳ» RETURN_ADDR_RTXÀÇ Á¤ÀǴ Ʋ¸®´Ù. __unwind_function¿¡ °üÇÑ ÀÚ¼¼ÇÑ »çÇ׿¡ ´ëÇؼ´Â ¾Æ·¡¸¦ º¸¶ó. &&°ú || expr¿¡ ´ëÇÑ EH cond º¯¼ö¸¦ À§ÇÑ RTL_EXPR´Â ¾î¼¸é UNSAVE_EXPR¾È¿¡ µÑ·¯½Î¿©¾ß ÇÑ´Ù. ±×¸®°í RTL_EXPRÀº ±×°ÍµéÀÌ ±¸Á¦µÉ ¼ö ¾øµµ·Ï(unsaved) Á¶Á¤µÇ¾î¾ß ÇÑ´Ù.
¿ì¸®´Â ¿ÀÁ÷ ¿¹¿Ü ¸ÅĪ a la 15.3 p2 case3¿¡ °üÇÑ Æ÷ÀÎÅÍ º¯È¯¸¸ ÇàÇÑ´Ù: 'type T, const T, T&, const T&¸¦ °¡Áø Çڵ鷯´Â ¸¸¾à [3]T°¡ Æ÷ÀÎÅÍ ÇüÀÌ°í private³ª protected base Ŭ·¡½º¿¡ ´ëÇÑ Æ÷ÀÎÅÍÀÇ º¯È¯À» Æ÷ÇÔÇÏÁö ¾Ê´Â Ç¥ÁØ Æ÷ÀÎÅÍ º¯È¯(_conv.prt_)¿¡ ÀÇÇØ T·Î º¯È¯µÉ ¼ö ÀÖ´Â Æ÷ÀÎÅÍÇüÀ̶ó¸é type EÀÇ °´Ã¼¸¦ °¡Áø ½º·Î¿ì Ç¥Çö¿¡ ´ëÇÑ ÇÑ Â¦ÀÌ´Ù.' E°¡ -frtti°¡ ÁÖ¾îÁú¶§
ctor°¡ ¿¹¿Ü¸¦ ½º·Î¿ìÇ߱⶧¹®¿¡ Á×´Â »õ·Î¿î Ç¥Çö¿¡ ´ëÇØ delete¸¦ È£ÃâÇÏÁö ¾Ê´Â´Ù. ½ÃÇè »ç·Ê¿¡ ´ëÇØ except/18À» º¸¶ó.
15.2 para 13: ¸¸¾à Á¦¾î°¡ »ý¼ºÀÚ ¶Ç´Â ¼Ò¸êÀÚÀÇ function-try-blockÀÇ Çڵ鷯ÀÇ ³¡¿¡ µµ´ÞÇÑ´Ù¸é, ó¸®µÈ ¿¹¿Ü´Â Àç ½º·Î¿ìµÇ¾ß ÇÑ´Ù. ¹Ù·Î Áö±Ý. ±×°ÍÀº ¾Æ´Ï´Ù.
15.2 para 12: ¸¸¾à ¹Ýȯ ¹®ÀåÀÌ »ý¼ºÀÚÀÇ function-try-blockÀÇ Çڵ鷯¿¡ ³ªÅ¸³´Ù¸é, ±× ÇÁ·Î±×·¥Àº ³ª»Û ÇüÅ´Ù. ±×·¯³ª ÀÌ°ÍÀº Áø´ÜµÇÁö ¾Ê´Â´Ù.
15.2 para 11: ¸¸¾à function-try-blockÀÇ Çڵ鷯°¡ »ý¼ºÀÚ ¶Ç´Â ¼Ò¸êÀÚÀÇ ¸öü(body)¾ÈÀ¸·ÎÀÇ Á¡ÇÁ¸¦ Æ÷ÇÔÇÑ´Ù¸é, ±× ÇÁ·Î±×·¥Àº ³ª»Û ÇüÅ´Ù. ±×·¯³ª ÀÌ°ÍÀº Áø´ÜµÇÁö ¾Ê´Â´Ù.
15.2 para 9: ¿ÏÀüÈ÷ ±¸¼ºµÈ base Ŭ·¡½º¿Í °´Ã¼ÀÇ ¸â¹ö´Â ±× °´Ã¼¿¡ ´ëÇÑ »ý¼ºÀÚ¿Í ¼Ò¸êÀÚÀÇ function-try-blockÀÇ Çڵ鷯¸¦ µé¾î°¡±âÀü¿¡ Æı«µÈ´Ù´Â °ÍÀ» °Ë»çÇ϶ó.
¼¼Æ®(set) ºñ±³¸¦ ¼öÇàÇϵµ·Ï build_exception_variant´Â incoming list¸¦ Á¤·ÄÇØ¾ß ÇÑ´Ù. not exact list equality. type smashingÀº set unionÀ» ÀÌ¿ëÇÑ ¿¹¿Ü ±ÔÁ¤À» ±ú¶ß·Á¾ß ÇÑ´Ù.
½º·Î¿ìµÈ °´Ã¼´Â ÀϹÝÀûÀÎ ¹æ¹ýÀ¸·Î º¸Åë Èü(heap)¿¡ ÇÒ´çµÈ´Ù. ¸¸¾à Çϳª°¡ Èü °ø°£¿¡¼ ³ª¿Â´Ù¸é, °´Ã¼¸¦ ½º·Î¿ìÇϴ°ÍÀº ¾Æ¸¶ °áÄÚ µ¿ÀÛÇÏÁö ¾ÊÀ» °ÍÀÌ´Ù. ÀÌ°ÍÀº ¿¹¿Ü °´Ã¼¿¡ °üÇÑ Á¦¾î¸¦ °¡Áø track¿¡ __in_chrg ¸Å°³º¯¼ö¸¦ Àü´ÞÇÔÀ¸·Î½á ´Ù¼Ò ´À½¼ÇØÁú ¼ö ÀÖ´Ù. ½º·Î¿ìµÈ °´Ã¼´Â ±×°ÍµéÀÌ °´Ã¼Çü¿¡ ´ëÇÑ Æ÷ÀÎÅÍÀ϶§ Èü¿¡ ÇÒ´çµÇÁö ¾Ê´Â´Ù. ¿ì¸®´Â ¸ðµç ÀÛÀº (<4*sizeof(void*)) °´Ã¼°¡ Èü¿¡ ÇÒ´çµÇ´Â ´ë½Å¿¡ Á÷Á¢ ÀúÀåµÇµµ·Ï ±×°ÍÀ» È®ÀåÇØ¾ß ÇÑ´Ù.
backend°¡ °ªÀ» ¹ÝȯÇÒ¶§, ±×°ÍÀº º¸È£°¡ ÇÊ¿äÇÑ »õ·Î¿î ¿¹¿Ü ¿µ¿ªÀ» »ý¼ºÇÒ ¼ö ÀÖ´Ù. ±× »õ·Î¿î ¿µ¿ªÀº ¿Ï¼ºµÈ last associated cleanupÀÇ ¹®¸Æ³» °´Ã¼¸¦ Àç ½º·Î¿ìÇØ¾ß ÇÑ´Ù.
C++ ¿¹¿Ü ó¸® Äڵ带 À§ÇØ »ý¼ºµÈ ÄÚµåÀÇ ±¸Á¶¸¦ ¾Æ·¡ º¸ÀδÙ:
Ln: throw value; copy value onto heap jump throw (Ln, id, address of copy of value on heap) try { +Lstart: the start of the main EH region |... ... +Lend: the end of the main EH region } catch (T o) { ...1 } Lresume: nop used to make sure there is something before the next region ends, if there is one ... ... jump Ldone [ Lmainhandler: handler for the region Lstart-Lend cleanup ] zero or more, depending upon automatic vars with dtors +Lpartial: | jump Lover +Lhere: rethrow (Lhere, same id, same obj); Lterm: handler for the region Lpartial-Lhere call terminate Lover: [ [ call throw_type_match if (eq) { ] these lines disappear when there is no catch condition +Lsregion2: | ...1 | jump Lresume |Lhandler: handler for the region Lsregion2-Leregion2 | rethrow (Lresume, same id, same obj); +Leregion2 } ] there are zero or more of these sections, depending upon how many catch clauses there are ----------------------------- expand_end_all_catch -------------------------- here we have fallen off the end of all catch clauses, so we rethrow to outer rethrow (Lresume, same id, same obj); ----------------------------- expand_end_all_catch -------------------------- [ L1: maybe throw routine ] depending upon if we have expanded it or not Ldone: ret start_all_catch emits labels: Lresume,
__unwind_functionÀº ½º·Î¿ì Çڵ鷯¿¡ ´ëÇÑ Æ÷ÀÎÅ͸¦ °¡Áø´Ù. ±×¸®°í ÇÁ·¹ÀÓ ¹Ù´Ú°ú ½º·Î¿ì Çڵ鷯±îÁö Á¡ÇÁ»Ó¸¸ ¾Æ´Ï¶ó ±×°ÍÀ» È£ÃâÇϱâ À§ÇØ ¸¸µé¾îÁø ½ºÅà ÇÁ·¹ÀÓÀ» ÆË(pop)Çϸ®¶ó°í ¿¹»óµÈ´Ù. ±× ¾ÈÀ¸·Î unwindingÇÏ°í ÀÖ´Â ¹®¸Æ(context)¿¡ ÀÇÇØ °áÁ¤µÈ °Í°ú °°ÀÌ ¸ðµç ´Ù¸¥ ±â°è »óÅ»Ӹ¸ ¾Æ´Ï¶ó ±×µéÀÇ Àû´çÇÑ °ªÀ¸·Î ¸ðµç ·¹Áö½ºÅ͸¦ ÀçÀúÀåÇØ¾ß ÇÑ´Ù. ³»°¡ ÀϹÝÀûÀ¸·Î ½ÃÀÛÇÏ´Â ¹æ¹ýÀº ´ÙÀ½À» ÄÄÆÄÀÏ ÇÏ´Â °ÍÀÌ´Ù:
void *g; foo(void* a) { g = a; }
-S¸¦ °¡Áö°í, PC¸¦ º¯°æÇÏÁö ¾Êµµ·Ï PC¸¦ ¹Ù²Ù´Â °Íµé(ÀϹÝÀûÀ¸·Î return ¶Ç´Â ret)À» º¯°æÇ϶ó. ²À ¸ðµç ´Ù¸¥ Àǹ̷Ð(½ºÅà Æ÷ÀÎÅͳª ÇÁ·¹ÀÓ Æ÷ÀÎÅ͸¦ Á¶Á¤ÇÏ´Â°Í °°ÀÌ)À» ³²°ÜµÎ¾î¶ó. ±× ÀÌÈÄ ³¡¿¡¼ Çѹø´õ prologue¸¦ º¹Á¦Ç϶ó. ¶Ç ¸í·ÉÀ» ¹Ù²Ù´Â PC¸¦ º¯°æÇ϶ó. ±×¸®°í ÃÖÁ¾ÀûÀ¸·Î ¹Ù·Î ±× ³¡¿¡¼ 'g'±îÁö Á¡ÇÁÇ϶ó.
ÀÌ ·çƾÀ» ÀÛ¼ºÇÏ´Â °ÍÀº ¾à ÀÏÁÖÀÏÀÌ °É¸°´Ù. ¸¸¾à ´©±º°¡°¡ ¾î¶°ÇÑ ¾ÆÅ°ÅØÃÄ(architecture)¿¡ ´ëÇÑ ÀÌ ·çƾÀ» ÀÛ¼ºÇÏ´Â °ÍÀ» ÀÚ¿øÇϱ⸦ ¿øÇÑ´Ù¸é, ±× ¾ÆÅ°ÅØÃÄ¿¡ ´ëÇÑ ¿¹¿Ü Áö¿øÀº g++¿¡ Ãß°¡µÉ °ÍÀÌ´Ù. ±×·¯ÇÑ ÄÚµå ±âÁõ¹°À» º¸³»Áֽʽÿä. ¼öÇàµÉ ÇÊ¿ä°¡ ÀÖ´Â ´Ù¸¥ °ÍÀº __builtin_return_address (0)°¡ µ¿ÀÛÇÏ´Â °ÍÀ» ÀÌÁß °Ë»çÇÏ´Â °ÍÀÌ´Ù.
For the alpha, the __unwind_function will be something resembling:
void __unwind_function(void *ptr) { /* First frame */ asm ("ldq $15, 8($30)"); /* get the saved frame ptr; 15 is fp, 30 is sp */ asm ("bis $15, $15, $30"); /* reload sp with the fp we found */ /* Second frame */ asm ("ldq $15, 8($30)"); /* fp */ asm ("bis $15, $15, $30"); /* reload sp with the fp we found */ /* Return */ asm ("ret $31, ($16), 1"); /* return to PTR, stored in a0 */ }
However, there are a few problems preventing it from working. First of
all, the gcc-internal function __builtin_return_address
needs to
work given an argument of 0 for the alpha. As it stands as of August
30th, 1995, the code for BUILT_IN_RETURN_ADDRESS
in `expr.c'
will definitely not work on the alpha. Instead, we need to define
the macros DYNAMIC_CHAIN_ADDRESS
(maybe),
RETURN_ADDR_IN_PREVIOUS_FRAME
, and definitely need a new
definition for RETURN_ADDR_RTX
.
In addition (and more importantly), we need a way to reliably find the
frame pointer on the alpha. The use of the value 8 above to restore the
frame pointer (register 15) is incorrect. On many systems, the frame
pointer is consistently offset to a specific point on the stack. On the
alpha, however, the frame pointer is pushed last. First the return
address is stored, then any other registers are saved (e.g., s0
),
and finally the frame pointer is put in place. So fp
could have
an offset of 8, but if the calling function saved any registers at all,
they add to the offset.
The only places the frame size is noted are with the `.frame'
directive, for use by the debugger and the OSF exception handling model
(useless to us), and in the initial computation of the new value for
sp
, the stack pointer. For example, the function may start with:
lda $30,-32($30) .frame $15,32,$26,0
The 32 above is exactly the value we need. With this, we can be sure
that the frame pointer is stored 8 bytes less--in this case, at 24(sp)).
The drawback is that there is no way that I (Brendan) have found to let
us discover the size of a previous frame inside the definition
of __unwind_function
.
So to accomplish exception handling support on the alpha, we need two
things: first, a way to figure out where the frame pointer was stored,
and second, a functional __builtin_return_address
implementation
for except.c to be able to use it.
Or just support DWARF 2 unwind info.
This subsection discusses various aspects of the design of the data-driven model being implemented for the exception handling backend.
The goal is to generate enough data during the compilation of user code,
such that we can dynamically unwind through functions at run time with a
single routine (__throw
) that lives in libgcc.a, built by the
compiler, and dispatch into associated exception handlers.
This information is generated by the DWARF 2 debugging backend, and includes all of the information __throw needs to unwind an arbitrary frame. It specifies where all of the saved registers and the return address can be found at any point in the function.
Major disadvantages when enabling exceptions are:
The backend must be extended to fully support exceptions. Right now there are a few hooks into the alpha exception handling backend that resides in the C++ frontend from that backend that allows exception handling to work in g++. An exception region is a segment of generated code that has a handler associated with it. The exception regions are denoted in the generated code as address ranges denoted by a starting PC value and an ending PC value of the region. Some of the limitations with this scheme are:
The above is not meant to be exhaustive, but does include all things I have thought of so far. I am sure other limitations exist.
Below are some notes on the migration of the exception handling code backend from the C++ frontend to the backend.
NOTEs are to be used to denote the start of an exception region, and the end of the region. I presume that the interface used to generate these notes in the backend would be two functions, start_exception_region and end_exception_region (or something like that). The frontends are required to call them in pairs. When marking the end of a region, an argument can be passed to indicate the handler for the marked region. This can be passed in many ways, currently a tree is used. Another possibility would be insns for the handler, or a label that denotes a handler. I have a feeling insns might be the best way to pass it. Semantics are, if an exception is thrown inside the region, control is transferred unconditionally to the handler. If control passes through the handler, then the backend is to rethrow the exception, in the context of the end of the original region. The handler is protected by the conventional mechanisms; it is the frontend's responsibility to protect the handler, if special semantics are required.
This is a very low level view, and it would be nice is the backend supported a somewhat higher level view in addition to this view. This higher level could include source line number, name of the source file, name of the language that threw the exception and possibly the name of the exception. Kenner may want to rope you into doing more than just the basics required by C++. You will have to resolve this. He may want you to do support for non-local gotos, first scan for exception handler, if none is found, allow the debugger to be entered, without any cleanups being done. To do this, the backend would have to know the difference between a cleanup-rethrower, and a real handler, if would also have to have a way to know if a handler `matches' a thrown exception, and this is frontend specific.
The stack unwinder is one of the hardest parts to do. It is highly machine dependent. The form that kenner seems to like was a couple of macros, that would do the machine dependent grunt work. One preexisting function that might be of some use is __builtin_return_address (). One macro he seemed to want was __builtin_return_address, and the other would do the hard work of fixing up the registers, adjusting the stack pointer, frame pointer, arg pointer and so on.
operator new []
adds a magic cookie to the beginning of arrays
for which the number of elements will be needed by operator delete
[]
. These are arrays of objects with destructors and arrays of objects
that define operator delete []
with the optional size_t argument.
This cookie can be examined from a program as follows:
typedef unsigned long size_t; extern "C" int printf (const char *, ...); size_t nelts (void *p) { struct cookie { size_t nelts __attribute__ ((aligned (sizeof (double)))); }; cookie *cp = (cookie *)p; --cp; return cp->nelts; } struct A { ~A() { } }; main() { A *ap = new A[3]; printf ("%ld\n", nelts (ap)); }
The linkage code in g++ is horribly twisted in order to meet two design goals:
1) Avoid unnecessary emission of inlines and vtables.
2) Support pedantic assemblers like the one in AIX.
To meet the first goal, we defer emission of inlines and vtables until the end of the translation unit, where we can decide whether or not they are needed, and how to emit them if they are.
alpha¿¡ ´ëÇؼ __unwind_functionÀº ´àÀº °ÍÀÌ µÉ °ÍÀÌ´Ù:
void __unwind_function(void *ptr) { /* First frame */ asm ("ldq $15, 8($30)"); /* get the saved frame ptr; 15 is fp, 30 is sp */ asm ("bis $15, $15, $30"); /* reload sp with the fp we found */ /* Second frame */ asm ("ldq $15, 8($30)"); /* fp */ asm ("bis $15, $15, $30"); /* reload sp with the fp we found */ /* Return */ asm ("ret $31, ($16), 1"); /* return to PTR, stored in a0 */ }
±×·¯³ª ¸î°¡Áö ¹®Á¦Á¡µéÀÌ µ¿ÀÛÀ» ¹æÇØÇÑ´Ù. ¹«¾ùº¸´Ùµµ gcc-³»ºÎ ÇÔ¼ö __builtin_return_address
´Â alpha¿¡ ´ëÇØ ÁÖ¾îÁø 0ÀÇ ÀÎÀÚ¸¦ µ¿ÀÛÇØ¾ß ÇÑ´Ù.
ÇöÀç·Î´Â 1995³â 8¿ù 30ÀÏÀÇ °ÍÀÌ´Ù. `expr.c'¿¡¼ BUILT_IN_RETURN_ADDRESS
¿¡ ´ëÇÑ ÄÚµå´Â alpha»ó¿¡¼ È®½ÇÈ÷ µ¿ÀÛÇÏÁö ¾Ê´Â´Ù.
±× ´ë½Å¿¡ ¸ÅÅ©·Î DYNAMIC_CHAIN_ADDRESS
(¾î¼¸é), RETURN_ADDR_IN_PREVIOUS_FRAME
¸¦ Á¤ÀÇÇؾßÇÑ´Ù. ±×¸®°í RETURN_ADDR_RTX
¿¡ ´ëÇÑ »õ·Î¿î Á¤ÀÇ°¡ ²À ÇÊ¿äÇÏ´Ù.
°Ô´Ù°¡(±×¸®°í Á»´õ Áß¿äÇÏ°Ô) alpha¿¡ °üÇÑ ÇÁ·¹ÀÓ Æ÷ÀÎÅ͸¦ È®½ÇÈ÷ ãÀ» ¼ö ÀÖ´Â ¹æ¹ýÀÌ ÇÊ¿äÇÏ´Ù.
ÇÁ·¹ÀÓ Æ÷ÀÎÅÍ(·¹Áö½ºÅÍ 15)¸¦ ÀçÀúÀåÇϱâÀ§ÇØ À§ 8 °ªÀ» »ç¿ëÇÏ´Â °ÍÀº Ʋ¸°°ÍÀÌ´Ù.
¸¹Àº ½Ã½ºÅÛ»ó¿¡¼ ÇÁ·¹ÀÓ Æ÷ÀÎÅÍ´Â ½ºÅûóÀÇ Æ¯Á¤ ÁöÁ¡¿¡ ´ëÇÑ ÀÏ°üµÈ ¿ÀÇÁ¼Â(offset)ÀÌ´Ù.
±×·¯³ª alpha»ó¿¡¼ ÇÁ·¹ÀÓ Æ÷ÀÎÅÍ´Â ³¡À¸·Î ¹Ð·Á°£´Ù. ¿ì¼± ¹Ýȯ ¹øÁö°¡ ÀúÀåµÇ°í, ±×´ÙÀ½ ´Ù¸¥ ·¹Áö½ºÅÍ°¡ ÀúÀåµÈ´Ù(¿¹¸¦ µé¸é, s0
).
±×¸®°í ¸¶Áö¸·À¸·Î ÇÁ·¹ÀÓ Æ÷ÀÎÅÍ´Â Àû¼Ò¿¡ ³õÀδÙ. ±×·¡¼ fp
´Â 8ÀÇ ¿ÀÇÁ¼ÂÀ» °¡Áú ¼ö ÀÖ´Ù.
±×·¯³ª ¸¸¾à È£ÃâÇÏ´Â ÇÔ¼ö°¡ ¾î¶² ·¹Áö½ºÅ͸¦ Á¶±ÝÀÌ¶óµµ ÀúÀåÇß´Ù¸é ±×°ÍµéÀº ¿ÀÇÁ¼Â¿¡ Ãß°¡µÈ´Ù.
ÇÁ·¹ÀÓ Å©±â°¡ ÀûÈù À¯ÀÏÇÑ Àå¼Ò´Â µð¹ö°Å¿Í (¿ì¸®¿¡°Ô ÇÊ¿ä¾ø´Â) OSF ¿¹¿Ü ó¸® ¸ðµ¨¿¡ ÀÇÇØ »ç¿ëÀ» À§ÇØ,
½ºÅÃÆ÷ÀÎÅÍ sp
¸¦ À§ÇÑ »õ·Î¿î °ªÀÇ Ãʱ⠰è»ê¿¡¼ `.frame' Áö½Ã¹®À» °¡Áö°í ÀÖ´Ù. ¿¹·Î½á, ÇÔ¼ö´Â ´ÙÀ½À» °¡Áö°í ½ÃÀÛÇÒÁöµµ ¸ð¸¥´Ù:
lda $30,-32($30) .frame $15,32,$26,0
À§ 32Àº ¿ì¸®°¡ ÇÊ¿ä·Î ÇÏ´Â ¹Ù·Î ±× °ªÀÌ´Ù. ÀÌ°ÍÀ» °¡Áö°í, ÇÁ·¹ÀÓ Æ÷ÀÎÅÍ´Â 8 ¹ÙÀÌÆ®ÀÌÇÏ·Î ÀúÀåµÈ´Ù´Â °ÍÀ» È®½ÅÇÒ ¼ö ÀÖ´Ù.
-- ÀÌ °æ¿ì¿¡ 24(sp)¿¡¼. ´ÜÁ¡Àº ³»(Brendan)°¡ __unwind_function
ÀÇ Á¤Àdz»¿¡¼ ÀÌÀü ÇÁ·¹ÀÓÀÇ Å©±â¸¦ ¾Ëµµ·Ï Çϴ°ÍÀ» ãÀ» ¹æ¹ýÀÌ ¾ø´Ù´Â °ÍÀÌ´Ù.
alpha¿¡ ´ëÇÑ ¿¹¿Ü ó¸® Áö¿øÀ» ÀÌ·ç±âÀ§ÇØ µÎ°¡Áö°¡ ÇÊ¿äÇÏ´Ù:
ù¹ø°´Â ÇÁ·¹ÀÓ Æ÷ÀÎÅÍ°¡ ¾îµð¿¡ ÀúÀå‰ç´ÂÁö¸¦ ¾Æ´Â ¹æ¹ý, µÎ¹ø°´Â ±×°ÍÀ» »ç¿ëÇÒ ¼ö ÀÖ´Â except.c¿¡ ´ëÇÑ functional __builtin_return_address
±¸ÇöÀÌ´Ù.
¶Ç´Â ´ÜÁö DWARF 2 unwind info¸¦ Áö¿øÇÑ´Ù.
¿©±â¼´Â ¿¹¿Ü ó¸® backend¸¦ À§ÇØ ±¸ÇöµÈ µ¥ÀÌŸ ±¸µ¿ ¸ðµå(data-driven mode)ÀÇ ¼³°èÀÇ ´Ù¾çÇÑ ¾ç»óÀ» ÅäÀÇÇÑ´Ù.
¸ñÀûÀº »ç¿ëÀÚ ÄÚµåÀÇ ÄÄÆÄÀÏ µ¿¾È¿¡ ÃæºÐÇÑ µ¥ÀÌŸ¸¦ »ý¼ºÇÏ´Â °ÍÀÌ´Ù.
ÄÄÆÄÀÏ·¯¿¡ ÀÇÇØ ¸¸µé¾îÁø libgcc.a¿¡ ÀÖ°í ¿¹¿Ü Çڵ鷯¾ÈÀ¸·Î µð½ºÆÐÄ¡ÇÏ´Â ´ÜÀÏ ·çƾ(__throw
)À» °¡Áö°í ½ÇÇà ½Ã°£¿¡ ÇÔ¼ö¸¦ ÅëÇØ µ¿ÀûÀ¸·Î unwindÇÒ ¼ö ÀÖ´Ù.
ÀÌ·¯ÇÑ Á¤º¸´Â DWARF 2 µð¹ö±ë backend¿¡ ÀÇÇØ »ý¼ºµÈ´Ù. ±×¸®°í __throw°¡ ÀÓÀÇÀÇ ÇÁ·¹ÀÓÀ» unwindÇؾßÇÑ´Ù´Â Á¤º¸¿¡ °üÇÑ ¸ðµç °ÍÀ» Æ÷ÇÔÇÑ´Ù. ±×°ÍÀº ¸ðµç ÀúÀåµÈ ·¹Áö½ºÅÍ¿Í º¹±Í ¹øÁö°¡ ÇÔ¼ö³» ¾îµð¿¡¼ ¹ß°ßµÉ ¼ö ÀÖ´ÂÁö¸¦ ¸í±âÇÑ´Ù.
¿¹¿Ü°¡ È°¼ºÈµÉ¶§ÀÇ ÁÖ¿äÇÑ ¼Õ½ÇÀº ´ÙÀ½°ú °°´Ù:
backend´Â ¿¹¿Ü¸¦ ÀüÀûÀ¸·Î Áö¿øÇϱâÀ§ÇØ È®ÀåµÇ¾î¾ß ÇÑ´Ù. ¹Ù·ÎÁö±Ý g++¿¡¼ µ¿ÀÛÇÏ´Â ¿¹¿Ü 󸮸¦ Çã¿ëÇÏ´Â backend·Î ºÎÅÍ C++ frontend¿¡ Á¸ÀçÇÏ´Â alpha ¿¹¿Ü ó¸® backend¿¡ ¸î°¡Áö ÈÅ(hook)ÀÌ ÀÖ´Ù. ¿¹¿Ü ¿µ¿ªÀº ±×°Í°ú ¿¬°üµÈ Çڵ鷯¸¦ °¡Áø »ý¼ºµÈ ÄÚµåÀÇ ¼¼±×¸ÕÆ®ÀÌ´Ù. ¿¹¿Ü ¿µ¿ªÀº ¿µ¿ªÀÇ ½ÃÀÛ PC°ª°ú ³¡ PC°ª¿¡ ÀÇÇØ Ç¥½ÃµÈ ¹øÁö ¹üÀ§·Î½á »ý¼ºµÈ Äڵ忡 Ç¥½ÃµÈ´Ù. ÀÌ·¯ÇÑ ±¸¼ºÀÌ °¡Áö´Â ¸î°¡Áö Á¦ÇÑÀº ´ÙÀ½°ú °°´Ù:
À§´Â öÀúÇÏ°Ô µÈ´Ù´Â Àǹ̴ ¾Æ´Ï¶ó ³»°¡ Áö±Ý±îÁö »ý°¢ÇÑ ¸ðµç °ÍµéÀ» Æ÷ÇÔÇÑ´Ù´Â °ÍÀÌ´Ù. Ʋ¸²¾øÀÌ ´Ù¸¥ Á¦ÇÑÀÌ Á¸ÀçÇÑ´Ù.
¾Æ·¡´Â C++ frontend·ÎºÎÅÍ backend±îÁö ¿¹¿Ü ó¸® ÄÚµå backendÀÇ À̵¿¿¡ °üÇÑ ¸î°¡Áö ±â·ÏÀÌ´Ù.
NOTE´Â ¿¹¿Ü ¿µ¿ªÀÇ ½ÃÀÛ°ú ³¡À» Ç¥½ÃÇϴµ¥ »ç¿ëµÉ ¿¹Á¤ÀÌ´Ù. ³ª´Â backend¿¡¼ À̵é note¸¦ »ý¼ºÇϴµ¥ »ç¿ëµÈ ÀÎÅÍÆäÀ̽º°¡ µÎ ÇÔ¼ö(start_exception_region°ú end_exception_region(¶Ç´Â ±×¿Í °°Àº °Í))ÀÏ °ÍÀ̶ó°í »ý°¢ÇÑ´Ù. frontend´Â ±×°ÍµéÀ» ½ÖÀ¸·Î È£ÃâÇϵµ·Ï ¿ä±¸µÈ´Ù. ¿µ¿ªÀÇ ³¡À» Ç¥½ÃÇÒ ¶§, ÀÎÀڴ ǥ½ÃµÈ ¿µ¿ªÀ» À§ÇØ Çڵ鷯¸¦ °¡¸®Å°±âÀ§ÇØ Åë°úµÉ ¼ö ÀÖ´Ù. ÀÌ°ÍÀº ¿©·¯°¡Áö ¹æ¹ýÀ¸·Î Åë°úµÉ ¼ö ÀÖ´Ù. ÇöÀç´Â Æ®¸®°¡ »ç¿ëµÈ´Ù. ´Ù¸¥ °¡´É¼ºÀº Çڵ鷯¿¡ ´ëÇÑ insns°¡ µÇ°Å³ª Çڵ鷯¸¦ ³ªÅ¸³»´Â ¶óº§(label)ÀÌ µÈ´Ù. ³ª´Â insns°¡ ±×°ÍÀ» Åë°úÇÏ´Â °¡Àå ÁÁÀº ¹æ¹ýÀ̶ó´Â ´À³¦À» °¡Áö°í ÀÖ´Ù. Àǹ̷ÐÀº ´ÙÀ½°ú °°´Ù. ¸¸¾à ¿¹¿Ü°¡ ±× ¿µ¿ª³»¿¡ ½º·Î¿ìµÈ´Ù¸é, Á¦¾î´Â Çڵ鷯¿¡°Ô ¹«Á¶°Ç Àü´ÞµÈ´Ù. ¸¸¾à Á¦¾î°¡ Çڵ鷯¸¦ ÅëÇØ Áö³ª°£´Ù¸é, backend´Â ¿ø·¡ ¿µ¿ªÀÇ ³¡ÀÇ ¹®¸Æ¿¡¼ ¿¹¿Ü¸¦ Àç ½º·Î¿ìÇÒ °ÍÀÌ´Ù. Çڵ鷯´Â ÀüÅëÀûÀÎ ¸ÞÄ¿´ÏÁò¿¡ ÀÇÇØ º¸È£µÈ´Ù; ¸¸¾à Ưº°ÇÑ Àǹ̷ÐÀÌ ¿ä±¸µÈ´Ù¸é Çڵ鷯¸¦ º¸È£ÇÏ´Â °ÍÀº frontendÀÇ Ã¥ÀÓÀÌ´Ù.
ÀÌ°ÍÀº ¸Å¿ì ³·Àº ¼öÁØÀÇ °üÁ¡ÀÌ´Ù. ±×¸®°í ±×°ÍÀº ÀÌ °üÁ¡¿¡ ´õÇÏ¿© ´Ù¼Ò ´õ ³ôÀº ¼öÁØÀÇ °üÁ¡ÀÌ Áö¿øµÇ´Â backend°¡ ÁÁÀ» °ÍÀÌ´Ù. ÀÌ·¯ÇÑ ´õ ³ôÀº ¼öÁØÀº source line number, ¿ø½ÃÆÄÀÏ À̸§, ¿¹¿Ü¸¦ ½º·Î¿ìÇÑ ¾ð¾îÀÇ À̸§°ú ¾î¼¸é ¿¹¿ÜÀÇ À̸§À» Æ÷ÇÔÇÑ´Ù. Kenner´Â C++¿¡ ÀÇÇØ ´ÜÁö ¿ä±¸µÇ´Â ±âº»»çÇ׺¸´Ù ´õ ¸¹ÀÌ Çϵµ·Ï ´ç½ÅÀ» ¿Ã°¡¸ÈÁöµµ ¸ð¸¥´Ù. ´ç½ÅÀ» ÀÌ°ÍÀ» ÇØ°áÇØ¾ß ÇÒ°ÍÀÌ´Ù. ±×°¡ ´ç½ÅÀÌ non-local goto¿¡ ´ëÇÑ Áö¿øÀ» Çϱ⸦ ¿øÇÒÁöµµ ¸ð¸¥´Ù. ¿¹¿Ü Çڵ鷯¿¡ ´ëÇÑ ÃÖÃÊ °Ë»öÀº ¸¸¾à ¾Æ¹«°Íµµ ãÁö ¸øÇÑ´Ù¸é ¿Ï·áµÈ ¾î¶°ÇÑ cleanup¾øÀÌ µð¹ö°Å°¡ ½ÃÀ۵ǵµ·Ï Çã¿ëÇÑ´Ù. ÀÌ°°ÀÌ ÇϱâÀ§ÇØ, backend´Â cleanup-rethrower¿Í ½ÇÁ¦ Çڵ鷯»çÀÌÀÇ Â÷À̸¦ ¾Ë¾Æ¾ß ÇÑ´Ù. ¸¸¾à Çڵ鷯°¡ ½º·Î¿ìµÈ ¿¹¿Ü¿¡ `¾î¿ï¸®´ÂÁö'¸¦ ¾Æ´Â ¹æ¹ýÀ» °¡Á®¾ß ÇÑ´Ù¸é ÀÌ°ÍÀº frontend specificÀÌ´Ù.
½ºÅà unwinder´Â ÇؾßÇÒ °¡Àå Èûµç ºÎºÐÁß ÇϳªÀÌ´Ù. Å©°Ô ±â°èÀÇÁ¸ÀûÀÌ´Ù. kenner°¡ ÁÁ¾ÆÇÏ´Â °Íó·³ º¸ÀÌ´Â ÇüÅ´ ±â°èÀÇÁ¸Àû grunt work¸¦ ÇÏ´Â ÇÑ ½ÖÀÇ ¸ÅÅ©·ÎÀÌ´Ù. °¡²û »ç¿ëµÉÁöµµ ¸ð¸£´Â Àü¿¡ Á¸ÀçÇÏ´ø ÇÔ¼ö´Â __builtin_return_address() ÀÌ´Ù. ±×°¡ ¿øÇß´ø ÇÑ ¸ÅÅ©·Î´Â __builtin_return_address ÀÌ°í ´Ù¸¥ Çϳª´Â ·¹Áö½ºÅ͸¦ °íÄ¡°í ½ºÅà Æ÷ÀÎÅÍ, ÇÁ·¹ÀÓ Æ÷ÀÎÅÍ, arg Æ÷ÀÎÅ͸¦ Á¶Á¤ÇÏ´Â µîÀÇ ¾î·Á¿î ÀÏÀ» ÇÑ´Ù.
¿¬»êÀÚ new[]
´Â ÀÎÀÚÀÇ ¼ö°¡ ¿¬»êÀÚ delete[]
¿¡ ÀÇÇØ ÇÊ¿äÇÏ°ÔµÉ ¹è¿ÀÇ Ã³À½¿¡ magic cookie¸¦ Ãß°¡ÇÑ´Ù.
À̰͵éÀº ¼Ò¸êÀÚ¸¦ °¡Áø °´Ã¼ÀÇ ¹è¿°ú optional size_t ÀÎÀÚ¸¦ °¡Áö°í ¿¬»êÀÚ delete []
¸¦ Á¤ÀÇÇÑ °´Ã¼ÀÇ ¹è¿ÀÌ´Ù.
ÀÌ cookie´Â ¾Æ·¡¿Í °°ÀÌ ÇÁ·Î±×·¥À¸·Î ºÎÅÍ Á¶»çµÉ ¼ö ÀÖ´Ù.
typedef unsigned long size_t; extern "C" int printf (const char *, ...); size_t nelts (void *p) { struct cookie { size_t nelts __attribute__ ((aligned (sizeof (double)))); }; cookie *cp = (cookie *)p; --cp; return cp->nelts; } struct A { ~A() { } }; main() { A *ap = new A[3]; printf ("%ld\n", nelts (ap)); }
g++¿¡¼ ¿¬°á ÄÚµå´Â µÎ°¡Áö ¼³°è ¸ñÇ¥¿¡ ¸ÂÃß±â À§ÇØ ²ûÂïÇÏ°Ô ²¿¿´´Ù:
1) inline¿Í vtableÀÇ ºÒÇÊ¿äÇÑ emissionÀ» ÇÇÇ϶ó.
2) AIX¿¡¼ ó·³ pedantic assembler¸¦ Áö¿øÇ϶ó.
ù¹ø° ¸ñÇ¥¿¡ ¸ÂÃß±â À§ÇØ ¹ø¿ª ÀåÄ¡(translation unit)ÀÇ Á¾·á±îÁö inline°ú vtableÀÇ emissionÀ» ¹Ì·é´Ù.
¿©±â¼ ¿ì¸®´Â ±×°ÍµéÀÌ ÇÊ¿äÇÑÁö ¾Æ´ÑÁö¸¦ °áÁ¤ÇÒ ¼ö ÀÖ´Ù. ±×¸®°í ¸¸¾à ÀÖ´Ù¸é ±×°ÍµéÀ» ¾î¶»°Ô emitÇÒÁö¸¦ °áÁ¤ÇÒ ¼ö ÀÖ´Ù.
Both C++ and Java provide overloaded functions and methods,
which are methods with the same types but different parameter lists.
Selecting the correct version is done at compile time.
Though the overloaded functions have the same name in the source code,
they need to be translated into different assembler-level names,
since typical assemblers and linkers cannot handle overloading.
This process of encoding the parameter types with the method name
into a unique name is called name mangling. The inverse
process is called demangling.
It is convenient that C++ and Java use compatible mangling schemes,
since the makes life easier for tools such as gdb, and it eases
integration between C++ and Java.
Note there is also a standard "Jave Native Interface" (JNI) which
implements a different calling convention, and uses a different
mangling scheme. The JNI is a rather abstract ABI so Java can call methods
written in C or C++;
we are concerned here about a lower-level interface primarily
intended for methods written in Java, but that can also be used for C++
(and less easily C).
Note that on systems that follow BSD tradition, a C identifier
C++ mangles a method by emitting the function name, followed by
For example
For a constructor, the method name is left out.
That is
GNU Java does the same.
The C++ types
The C++ and Java floating-point types
The C++
The C++
The Java integral types
C++ code that has included
A simple class, package, template, or namespace name is
encoded as the number of characters in the name, followed by
the actual characters. Thus the class
If any of the characters in the name are not alphanumeric
(i.e not one of the standard ASCII letters, digits, or '_'),
or the initial character is a digit, then the name is
mangled as a sequence of encoded Unicode letters.
A Unicode encoding starts with a `U' to indicate
that Unicode escapes are used, followed by the number of
bytes used by the Unicode encoding, followed by the bytes
representing the encoding. ASSCI letters and
non-initial digits are encoded without change. However, all
other characters (including underscore and initial digits) are
translated into a sequence starting with an underscore,
followed by the big-endian 4-hex-digit lower-case encoding of the character.
If a method name contains Unicode-escaped characters, the
entire mangled method name is followed by a `U'.
For example, the method
A C++ pointer type is mangled as `P' followed by the
mangling of the type pointed to.
A C++ reference type as mangled as `R' followed by the
mangling of the type referenced.
A Java object reference type is equivalent
to a C++ pointer parameter, so we mangle such an parameter type
as `P' followed by the mangling of the class name.
Squangling (enabled with the `-fsquangle' option), utilizes the
`B' code to indicate reuse of a previously seen type within an
indentifier. Types are recognized in a left to right manner and given
increasing values, which are appended to the code in the standard
manner. Ie, multiple digit numbers are delimited by `_'
characters. A type is considered to be any non primitive type,
regardless of whether its a parameter, template parameter, or entire
template. Certain codes are considered modifiers of a type, and are not
included as part of the type. These are the `C', `V',
`P', `A', `R', `U' and `u' codes, denoting
constant, volatile, pointer, array, reference, unsigned, and restrict.
These codes may precede a `B' type in order to make the required
modifications to the type.
For example:
Produces the mangled name `f__FGt6class21Zt6class11Z6class3iRCB1PB2'.
The int parameter is a basic type, and does not receive a B encoding...
Both C++ and Java allow a class to be lexically nested inside another
class. C++ also supports namespaces.
Java also supports packages.
These are all mangled the same way: First the letter `Q'
indicates that we are emitting a qualified name.
That is followed by the number of parts in the qualified name.
If that number is 9 or less, it is emitted with no delimiters.
Otherwise, an underscore is written before and after the count.
Then follows each part of the qualified name, as described above.
For example
Squangling utilizes the the letter `K' to indicate a
remembered portion of a qualified name. As qualified names are processed
for an identifier, the names are numbered and remembered in a
manner similar to the `B' type compression code.
Names are recognized left to right, and given increasing values, which are
appended to the code in the standard manner. ie, multiple digit numbers
are delimited by `_' characters.
For example
Function `f()' would be mangled as :
`f__FR6AndrewRQ2K07WasHereRQ2K110AndHereToo'
There are some occasions when either a `B' or `K' code could
be chosen, preference is always given to the `B' code. Ie, the example
in the section on `B' mangling could have used a `K' code
instead of `B2'.
A class template instantiation is encoded as the letter `t',
followed by the encoding of the template name, followed
the number of template parameters, followed by encoding of the template
parameters. If a template parameter is a type, it is written
as a `Z' followed by the encoding of the type. If it is a
template, it is encoded as `z' followed by the parameter
of the template template parameter and the template name.
A function template specialization (either an instantiation or an
explicit specialization) is encoded by an `H' followed by the
encoding of the template parameters, as described above, followed by an
`_', the encoding of the argument types to the template function
(not the specialization), another `_', and the return type. (Like
the argument types, the return type is the return type of the function
template, not the specialization.) Template parameters in the argument
and return types are encoded by an `X' for type parameters,
`zX' for template parameters,
or a `Y' for constant parameters, an index indicating their position
in the template parameter list declaration, and their template depth.
C++ array types are mangled by emitting `A', followed by
the length of the array, followed by an `_', followed by
the mangling of the element type. Of course, normally
array parameter types decay into a pointer types, so you
don't see this.
Java arrays are objects. A Java type
Both C++ and Java classes can have static fields.
These are allocated statically, and are shared among all instances.
The mangling starts with a prefix (`_' in most systems), which is
followed by the mangling
of the class name, followed by the "joiner" and finally the field name.
The joiner (see
For example
If the name of a static variable needs Unicode escapes,
the Unicode indicator `U' comes before the "joiner".
This
The following special characters are used in mangling:
The letters `G', `M', `O', and `p'
also seem to be used for obscure purposes ...
¿ø¹®½ÃÀÛ
Function name mangling for C++ and Java
var
would get "mangled" into the assembler name `_var'. On such
systems, all other mangled names are also prefixed by a `_'
which is not shown in the following examples.
Method name mangling
__
,
followed by encodings of any method qualifiers (such as const
),
followed by the mangling of the method's class,
followed by the mangling of the parameters, in order.
Foo::bar(int, long) const
is mangled
as `bar__C3Fooil'.
Foo::Foo(int, long) const
is mangled
as `__C3Fooil'.
Primitive types
int
, long
, short
, char
,
and long long
are mangled as `i', `l',
`s', `c', and `x', respectively.
The corresponding unsigned types have `U' prefixed
to the mangling. The type signed char
is mangled `Sc'.
float
and double
are mangled as `f' and `d' respectively.
bool
type and the Java boolean
type are
mangled as `b'.
wchar_t
and the Java char
types are
mangled as `w'.
byte
, short
, int
and long
are mangled as `c', `s', `i',
and `x', respectively.
javatypes.h
will mangle
the typedefs jbyte
, jshort
, jint
and jlong
as respectively `c', `s', `i',
and `x'. (This has not been implemented yet.)
Mangling of simple names
Foo
is encoded as `3Foo'.
X\u0319::M\u002B(int)
is encoded as
`M_002b__U6X_0319iU'.
Pointer and reference types
Squangled type compression
template <class T> class class1 { };
template <class T> class class2 { };
class class3 { };
int f(class2<class1<class3> > a ,int b, const class1<class3>&c, class3 *d) { }
B0 -> class2<class1<class3>
B1 -> class1<class3>
B2 -> class3
Qualified names
Foo::\u0319::Bar
is encoded as
`Q33FooU5_03193Bar'.
class Andrew
{
class WasHere
{
class AndHereToo
{
};
};
};
f(Andrew&r1, Andrew::WasHere& r2, Andrew::WasHere::AndHereToo& r3) { }
K0 -> Andrew
K1 -> Andrew::WasHere
K2 -> Andrew::WasHere::AndHereToo
Templates
Arrays
T[]
is mangled
as if it were the C++ type JArray<T>
.
For example java.lang.String[]
is encoded as
`Pt6JArray1ZPQ34java4lang6String'.
Static fields
JOINER
in cp-tree.h
) is a special
separator character. For historical reasons (and idiosyncracies
of assembler syntax) it can `$' or `.' (or even
`_' on a few systems). If the joiner is `_' then the prefix
is `__static_' instead of just `_'.
Foo::Bar::var
(or Foo.Bar.var
in Java syntax)
would be encoded as `_Q23Foo3Bar$var' or `_Q23Foo3Bar.var'
(or rarely `__static_Q23Foo3Bar_var').
\u1234Foo::var\u3445
becomes _U8_1234FooU.var_3445
.
Table of demangling code characters
bool
type,
and the Java boolean
type.
char
type, and the Java byte
type.
const
type.
Also used to indicate a const
member function
(in which cases it precedes the encoding of the method's class).
double
types.
...
.
float
types.
int
types.
intn_t
, where n is a
positive decimal number. The `I' is followed by either two
hexidecimal digits, which encode the value of n, or by an
arbitrary number of hexidecimal digits between underscores. For
example, `I40' encodes the type int64_t
, and `I_200_'
encodes the type int512_t
.
long
type.
long double
type.
short
types.
char
.
Also used as a modifier to indicate a static member function.
restrict
type qualifier.
void
types.
volatile
type or method.
wchar_t
type, and the Java char
types.
long long
type, and the Java long
type.
Concept Index
p
¿ø¹®³¡
C++°ú Java´Â µÑ´Ù ¿À¹ö·ÎµåµÈ ÇÔ¼ö¿Í ¸Þ¼µå¸¦ Á¦°øÇÑ´Ù. ±×¸®°í ÀÌ°ÍÀº °°Àº ÇüÀ» °¡ÁöÁö¸¸ ¸Å°³º¯¼ö ¸ñ·ÏÀÌ ´Ù¸£´Ù. ¿Ç¹Ù¸¥ ¹öÀüÀ» ¼±ÅÃÇÏ´Â °ÍÀº ÄÄÆÄÀÏ ½Ã°£¿¡ ¼öÇàµÈ´Ù. ¿À¹ö·ÎµåµÈ ÇÔ¼ö°¡ ¿ø½Ã ÄÚµå¾È¿¡ °°Àº À̸§À» °¡Áö°í ÀÖÀ»Áö¶óµµ ´Ù¸¥ assembler-level À̸§À¸·Î ¹ø¿ªµÇ¾ßÇÑ´Ù. ¿Ö³ÄÇϸé ÀüÇüÀûÀÎ ¾î¼Àºí·¯¿Í ¸µÄ¿´Â ¿À¹ö·Îµù(overloading)À» Ãë±ÞÇÒ ¼ö ¾ø±â¶§¹®ÀÌ´Ù. ¸Þ¼µå À̸§À» °¡Áø ¸Å°³º¯¼ö ÇüÀ» À¯ÀÏÇÑ À̸§À¸·Î ÀÎÄÚµùÇÏ´Â °úÁ¤À» name mangling¶ó°í ÀÏÄ´´Ù. ¹Ý´ë °úÁ¤À» demanglingÀ̶ó°í ÀÏÄ´´Ù.
C++°ú Java°¡ ȣȯ°¡´ÉÇÑ mangling ±¸¼ºÀ» »ç¿ëÇÏ´Â °ÍÀº Æí¸®ÇÏ´Ù. ¿Ö³ÄÇϸé gdb°°Àº ÅøÀ» ´õ ½±°Ô »ç¿ëÇϵµ·Ï ÇÏ°í, C++°ú Java »çÀÌÀÇ ÅëÇÕÀ» ½±°ÔÇÑ´Ù.
´Ù¸¥ È£Ãâ ±ÔÁ¤À» ½ÇÇàÇÏ°í ´Ù¸¥ mangling ±¸¼º(scheme)À» »ç¿ëÇϴ ǥÁØ "Java Native Interface" (JNI)°¡ ¶ÇÇÑ ÀÖ´Ù´Â °ÍÀ» ÁÖÁöÇ϶ó. JNI´Â »ó´çÈ÷ Ãß»óÀûÀÎ ABIÀÌ¾î¼ Java´Â C³ª C++·Î ÀÛ¼ºµÈ ¸Þ¼µå¸¦ È£ÃâÇÒ ¼ö ÀÖ´Ù: ¿©±â¼ ¿ì¸®´Â Java·Î ÀÛ¼ºµÈ ¸Þ¼µå¸¦ À§ÇØ ÃÖÃÊ·Î ÁöÁ¤µÈ lower-level interface¿¡ °ü½ÉÀÌ ÀÖ´Ù. ±×·¯³ª ±×°ÍÀº ¶ÇÇÑ C++¿¡ ´ëÇØ »ç¿ëµÉ ¼ö ÀÖ´Ù(±×¸®°í C¿¡¼´Â ´ú ½±°Ô »ç¿ëµÈ´Ù).
BSD traditionÀ» µû¸£´Â ½Ã½ºÅÛ»ó¿¡¼ C ½Äº°ÀÚ var
´Â ¾î¼Àºí·¯¸í `_var'·Î "mangle" µÉ °ÍÀÌ´Ù. ±×·± ½Ã½ºÅÛ¿¡¼ ¸ðµç ´Ù¸¥ mangled name´Â ¶ÇÇÑ ´ÙÀ½ ¿¹¿¡¼ º¸¿©ÁöÁö ¾ÊÀº `_'°¡ ¾Õ¿¡ ºÙ´Â´Ù.
C++Àº ÇÔ¼ö¸í, ´ÙÀ½¿¡ __
, ´ÙÀ½¿¡ ¾î¶² (const
°°Àº) ¸Þ¼µå qualifier, ´ÙÀ½¿¡ ¸Þ¼µå Ŭ·¡½ºÀÇ mangling, ´ÙÀ½¿¡ ¸Å°³º¯¼öÀÇ mangling ¼øÀ¸·Î emitÇÔÀ¸·Î½á ¸Þ¼µå¸¦ mangleÇÑ´Ù.
¿¹¸¦ µé¸é, Foo::bar(int, long) const
´Â `bar__C3Fooil'·Î mangleµÈ´Ù.
»ý¼ºÀÚ¿¡ ´ëÇØ, ¸Þ¼µå¸íÀº »ý·«µÈ´Ù. Áï, Foo::Foo(int, long) const
´Â `__C3Fooil'·Î mangleµÈ´Ù.
GNU Java´Â ¶È°°ÀÌ ÇàÇÑ´Ù.
C++ Çü int
, long
, short
, char
, long long
´Â `i', `l',`s', `c', `x'·Î °¢°¢ mangleµÈ´Ù.
´ëÀÀÇÏ´Â unsigned ÇüÀº manglingÇÑ°Í ¾Õ¿¡ `U'°¡ ºÙ´Â´Ù. signed char
Àº `Sc'·Î mangleµÈ´Ù.
C++°ú Java ºÎµ¿¼Ò¼öÁ¡ÇüÀÎ float
¿Í double
Àº °¢°¢ `f'¿Í `d'·Î mangleµÈ´Ù.
C++ bool
Çü°ú Java boolean
ÇüÀº `b'·Î mangleµÈ´Ù.
C++ wchar_t
°ú Java char
ÇüÀº `w'·Î mangleµÈ´Ù.
Java Á¤¼öÇüÀÎ byte
, short
, int
, long
´Â `c', `s', `i', `x'·Î °¢°¢ mangleµÈ´Ù.
javatypes.h
¸¦ Æ÷ÇÔÇÏ°í ÀÖ´Â C++ ÄÚµå´Â typedefÀÎ jbyte
, jshort
, jint
, jlong
¸¦ °¢°¢ `c', `s', `i', `x'·Î mangleÇÒ °ÍÀÌ´Ù.(ÀÌ°ÍÀº ¾ÆÁ÷ ±¸ÇöµÇÁö ¾Ê°í ÀÖ´Ù.)
°£´ÜÇÑ class, package, template, namespace ¸íÀº À̸§³» ¹®ÀÚ¼ö, ´ÙÀ½¿¡ ½ÇÁ¦ ¹®ÀÚ·Î ÄÚµåÈ µÈ´Ù. ÀÌ·¸µí Ŭ·¡½º Foo
´Â `3Foo'·Î ÄÚµåȵȴÙ.
À̸§³» ¹®ÀÚÁß ¾î¶² °ÍÀÌ alphanumeric(Áï, Ç¥ÁØ ASCII¹®ÀÚ, ¼ýÀÚ, ¶Ç´Â '_'ÁßÀÇ Çϳª°¡ ¾Æ´Ñ)ÀÌ ¾Æ´Ï°Å³ª óÀ½ ¹®ÀÚ°¡ ¼ýÀÚ¶ó¸é, À̸§Àº encoded Unicode ¹®ÀÚÀÇ ¿·Î½á mangleµÈ´Ù. Unicode ÀÎÄÚµùÀº Unicode escape°¡ »ç¿ëµÈ´Ù´Â °ÍÀ» °¡¸£Å°±âÀ§ÇØ `U'·Î ½ÃÀÛÇÑ´Ù. ´ÙÀ½¿¡ Unicode ÀÎÄÚµù¿¡ »ç¿ëµÈ ¹ÙÀÌÆ®¼ö, ´ÙÀ½¿¡ ÀÎÄÚµùÀ» Ç¥½ÃÇÏ´Â ¹ÙÀÌÆ®. ASCII ¹®ÀÚ¿Í ¸Ç¾Õ¿¡ À§Ä¡ÇÏÁö ¾Ê´Â ¼ýÀÚ´Â º¯°æ¾øÀÌ ÀÎÄÚµùµÈ´Ù. ±×·¯³ª (¸Ç¾Õ¿¡ À§Ä¡ÇÏ´Â ¼ýÀÚ¿Í ¹ØÁÙÀ» Æ÷ÇÔÇÏ´Â) ´Ù¸¥ ¸ðµç ¹®ÀÚµéÀº ¹ØÁÙÀ» °¡Áö°í ½ÃÀÛÇÏ´Â ¿·Î ¹ø¿ªµÈ´Ù. ´ÙÀ½¿¡ ¹®ÀÚÀÇ big-endian 4-hex-digit lower case encoding.
¸¸¾à ¸Þ¼µå¸íÀÌ Unicode-escaped ¹®ÀÚ¸¦ °¡Áö°í ÀÖ´Ù¸é, Àüü mangleµÈ ¸Þ¼µå¸í ´ÙÀ½¿¡ `U'°¡ ¿Â´Ù.
¿¹¸¦ µé¸é, ¸Þ¼µå X\u0319::M\u002B(int)
´Â `M_002b__U6X_0319iU'·Î ÀÎÄÚµùµÈ´Ù.
C++ Æ÷ÀÎÅÍÇüÀº `P' ´ÙÀ½¿¡ ÁöÁ¤µÈ ÇüÀÇ manglingÀ¸·Î mangleµÈ´Ù.
C++ ÂüÁ¶ÇüÀº `R' ´ÙÀ½¿¡ ÂüÁ¶µÈ ÇüÀÇ manglingÀ¸·Î mangleµÈ´Ù.
Java °´Ã¼ ÂüÁ¶ÇüÀº C++ Æ÷ÀÎÅÍ ¸Å°³º¯¼ö¿¡ ÇØ´çÇÑ´Ù. ±×·¡¼ `P' ´ÙÀ½¿¡ Ŭ·¡½º¸íÀÇ manglingÀ¸·Î ±×·± ¸Å°³º¯¼öÇüÀ» mangleÇÑ´Ù.
(`-fsquangle' ¿É¼ÇÀ¸·Î È°¼ºÈµÈ) squanglingÀº ½Äº°Àھȿ¡ Àü¿¡ º¸¿©Áø ÇüÀÇ Àç»ç¿ë(reuse)À» °¡¸£Å°´Âµ¥¿¡ `B' Äڵ带 ÀÌ¿ëÇÑ´Ù. ÇüÀº ¿ÞÂÊ¿¡¼ ¿À¸¥ÂÊÀ¸·ÎÀÇ ¹æ¹ý°ú Ç¥Áعæ¹ý¿¡¼ Äڵ忡 µ¡ºÙ¿©Áø ÁÖ¾îÁø Áõ°¡°ª¿¡¼ ÀνĵȴÙ. Áï, ¿©·¯ÀÚ¸®(multiple digit) ¼ýÀÚ´Â`_' ¹®ÀÚ·Î ±¸ºÐµÈ´Ù. ÇüÀº ±×°ÍÀÌ ¸Å°³º¯¼ö, ÅÛÇø´ ¸Å°³º¯¼ö ¶Ç´Â entire template°Ç »ó°ü¾øÀÌ ºñ¿øÇü(non primitive type)ÀÌ µÇ¸®¶ó »ý°¢µÈ´Ù. ¾î¶² ÄÚµå´Â ÇüÀÇ modifier·Î °í·ÁµÇ°í, ÇüÀÇ ÀϺηνá Æ÷ÇÔµÇÁö ¾Ê´Â´Ù. À̰͵éÀº `C', `V', `P', `A', `R', `U', `u' ÄÚµåÀÌ´Ù. »ó¼ö, volatile, Æ÷ÀÎÅÍ, ¹è¿, ÂüÁ¶, unsigned, restrict¸¦ ³ªÅ¸³½´Ù. À̵é ÄÚµå´Â Çü¿¡ ´ëÇÑ ÇÊ¿äÇÑ º¯°æÀ» ¼öÇàÇϱâÀ§ÇØ `B' Çü¿¡ ¾Õ¼³Áöµµ ¸ð¸¥´Ù.
¿¹¸¦ µé¸é:
template <class T> class class1 { }; template <class T> class class2 { }; class class3 { }; int f(class2<class1<class3> > a ,int b, const class1<class3>&c, class3 *d) { } B0 -> class2<class1<class3> B1 -> class1<class3> B2 -> class3
mangleµÈ À̸§ `f__FGt6class21Zt6class11Z6class3iRCB1PB2'¸¦ ¸¸µé¾î¶ó. Int ¸Å°³º¯¼ö´Â ±âº» ÇüÀÌ°í B ÀÎÄÚµùÀ» ¹ÞÁö ¾Ê´Â´Ù.
C++°ú Java´Â ÇÑ Å¬·¡½º°¡ ´Ù¸¥ Ŭ·¡½º³»¿¡ ¾îÀÇÀûÀ¸·Î ³õ¿©Áö´Â °ÍÀ» Çã¿ëÇÑ´Ù. C++Àº ¶ÇÇÑ namespace¸¦ Áö¿øÇÑ´Ù. Java´Â ¶ÇÇÑ package¸¦ Áö¿øÇÑ´Ù.
À̰͵éÀº ¸ðµÎ °°Àº ¹æ¹ýÀ¸·Î mangleµÈ´Ù: ¿ì¼± ¹®ÀÚ `Q'´Â ¿ì¸®°¡ qualified nameÀ» emitÇÏ°í ÀÖ´Ù´Â °ÍÀ» °¡¸£Å²´Ù. ±×°ÍÀº ±× ´ÙÀ½¿¡ qualified name³»¿¡ ºÎºÐ(part)ÀÇ ¼ö°¡ µû¶ó¿Â´Ù. ¸¸¾à ±× ¼ö°¡ 9ÀÌÇ϶ó¸é °æ°è±âÈ£¾øÀÌ emitµÈ´Ù. ¸¸¾à ±×·¸Áö ¾Ê´Ù¸é ¹ØÁÙÀÌ °è¼ö°ª Àü,ÈÄ¿¡ ¾²¿©Áø´Ù. ±×·±´ÙÀ½ À§¿¡¼ ¾ð±ÞÇÑ °Í°ú °°ÀÌqualified nameÀÇ °¢ ºÎºÐÀ» µû¸¥´Ù.
¿¹¸¦ µé¸é Foo::\u0319::Bar
´Â `Q33FooU5_03193Bar'·Î ÀÎÄÚµùµÈ´Ù.
squangling´Â qualified nameÀÇ ±â¾ïµÈ ºÎºÐÀ» °¡¸£Å°´Âµ¥ ¹®ÀÚ `K'¸¦ ÀÌ¿ëÇÑ´Ù. Qualified nameÀÌ ½Äº°ÀÚ¿¡ ´ëÇØ Ã³¸®µÉ ¶§, À̸§µéÀº °è¼öµÇ°í `B' Çü ¾ÐÃàÄڵ忡¼¿Í ºñ½ÁÇÑ ¹æ¹ýÀ¸·Î ±â¾ïµÈ´Ù. À̸§µéÀº ¿ÞÂÊ¿¡¼ ¿À¸¥ÂÊ, ±×¸®°í Ç¥Áعæ¹ý¿¡¼ Äڵ忡 µ¡ºÙ¿©Áø ÁÖ¾îÁø Áõ°¡°ª¿¡¼ ÀνĵȴÙ. Áï, Áï, ¿©·¯ÀÚ¸® ¼ýÀÚ´Â `_' ¹®ÀÚ·Î ±¸ºÐµÈ´Ù.
¿¹¸¦ µé¸é
class Andrew { class WasHere { class AndHereToo { }; }; }; f(Andrew&r1, Andrew::WasHere& r2, Andrew::WasHere::AndHereToo& r3) { } K0 -> Andrew K1 -> Andrew::WasHere K2 -> Andrew::WasHere::AndHereToo
ÇÔ¼ö `f()'´Â ´ÙÀ½°ú °°ÀÌ mangleµÉ °ÍÀÌ´Ù : `f__FR6AndrewRQ2K07WasHereRQ2K110AndHereToo'
`B'³ª `K' Äڵ尡 ¼±Åõɶ§ ¸î°¡Áö ±âȸ°¡ ÀÖ´Ù. ¿ì¼±±ÇÀº Ç×»ó `B' Äڵ忡°Ô ÁÖ¾îÁø´Ù. Áï, `B' mangling¿¡ °üÇÑ ÀýÀÇ ¿¹¿¡¼ `B2'´ë½Å¿¡ `K' Äڵ尡 »ç¿ëµÉ ¼ö ÀÖ¾úÀ» ÅÙµ¥.
Ŭ·¡½º ÅÛÇø´ instantiationÀº ¹®ÀÚ `t', ´ÙÀ½¿¡ ÅÛÇø´¸íÀÇ ÀÎÄÚµù, ´ÙÀ½¿¡ ÅÛÇø´ ¸Å°³º¯¼öÀÇ ¼ö, ´ÙÀ½¿¡ ÅÛÇø´ ¸Å°³º¯¼öÀÇ ÀÎÄÚµùÀ¸·Î½á ÀÎÄÚµùµÈ´Ù. ¸¸¾à ÅÛÇø´ ¸Å°³º¯¼ö°¡ Çü(type)À̶ó¸é `Z' ´ÙÀ½¿¡ ÇüÀÇ ÀÎÄÚµùÀ¸·Î ¾²¿©Áú °ÍÀÌ´Ù. ¸¸¾à ±×°ÍÀÌ ÅÛÇø´À̶ó¸é `z' ´ÙÀ½¿¡ ÅÛÇø´ ÅÛÇø´ ¸Å°³º¯¼öÀÇ ¸Å°³º¯¼ö¿Í ÅÛÇø´¸íÀ¸·Î ÀÎÄÚµùµÉ °ÍÀÌ´Ù.
ÇÔ¼ö ÅÛÇø´ specialization(instantiation°Å³ª explicit specialization°Å³ª)´Â `H' ´ÙÀ½¿¡ ÅÛÇø´ ¸Å°³º¯¼öÀÇ ÀÎÄÚµù,À§¿¡ ¾ð±ÞÇÑ °Í°ú °°ÀÌ, ´ÙÀ½¿¡ `_', ÅÛÇø´ ÇÔ¼ö(specializatioÀÌ ¾Æ´Ñ)¿¡ ´ëÇÑ ÀÎÀÚÇü(argument type)ÀÇ ÀÎÄÚµù, `_', ±ÍȯÇü(return type)À¸·Î ÀÎÄÚµùµÈ´Ù. (ÀÎÀÚÇü°ú °°ÀÌ ±ÍȯÇüÀº ÇÔ¼ö ÅÛÇø´ÀÇ ±ÍȯÇüÀÌ´Ù. specializationÀÇ °ÍÀÌ ¾Æ´Ï´Ù.) ÀÎÀÚ¿Í ±ÍȯÇü¿¡¼ ÅÛÇø´ ¸Å°³º¯¼ö´Â Çü ¸Å°³º¯¼ö(type parameter)¿¡ ´ëÇÑ `X', ÅÛÇø´ ¸Å°³º¯¼ö¿¡ ´ëÇÑ `zX', ¶Ç´Â »ó¼ö ¸Å°³º¯¼ö, ÅÛÇø´ ¸Å°³º¯¼ö ¸ñ·Ï ¼±¾ð¿¡¼ ±×°ÍµéÀÇ À§Ä¡¸¦ ³ªÅ¸³»´Â À妽º, ÅÛÇø´ depth¿¡ ´ëÇÑ `Y'¿¡ ÀÇÇØ ÀÎÄÚµùµÈ´Ù.
C++ ¹è¿ÇüÀº `A', ´ÙÀ½¿¡ ¹è¿ÀÇ ±æÀÌ, ´ÙÀ½¿¡ `_', ´ÙÀ½¿¡ ¿ä¼ÒÇü(element type)ÀÇ manglingÀ» emitÇÔÀ¸·Î½á mangleµÈ´Ù. ¹°·Ð, ÀϹÝÀûÀ¸·Î ¹è¿ ¸Å°³º¯¼öÇüÀº Æ÷ÀÎÅÍÇü¾È¿¡¼ ¼Ò¸êÇϹǷΠÀÌ°ÍÀ» º¼ ¼ö ¾ø´Ù.
Java ¹è¿Àº °´Ã¼ÀÌ´Ù. Java Çü T[]
´Â ¸¶Ä¡ C++ Çü JArray<T>
ó·³ mangleµÈ´Ù.
¿¹¸¦ µé¸é java.lang.String[]
´Â `Pt6JArray1ZPQ34java4lang6String'·Î mangleµÈ´Ù.
C++°ú Java Ŭ·¡½º´Â Á¤Àû Çʵ带 °¡Áú ¼ö ÀÖ´Ù. À̰͵éÀº Á¤ÀûÀ¸·Î ÇÒ´çµÈ´Ù. ±×¸®°í ¸ðµç ÀνºÅϽºµé¿¡°Ô °øÀ¯µÈ´Ù.
manglingÀº Á¢µÎ¾î(´ëºÎºÐ ½Ã½ºÅÛ¿¡¼ `_')¸¦ °¡Áö°í ½ÃÀÛÇÑ´Ù. ±×¸®°í ±×°Í ´ÙÀ½¿¡ Ŭ·¡½º¸íÀÇ mangling, ´ÙÀ½¿¡ "joiner"¿Í ¸¶Áö¸·À¸·Î Çʵå¸íÀÌ ¿Â´Ù.
joiner(cp-tree.h
¿¡¼ JOINER
¸¦ º¸¶ó)´Â Ưº°ÇÑ ºÐ¸®ÀÚ ¹®ÀÚ(separator character)ÀÌ´Ù.
¿ª»çÀû ÀÌÀ¯(±×¸®°í ¾î¼Àºí·¯ ±¸¹®ÀÇ Æ¯¼º) ¶§¹®¿¡ ±×°ÍÀº `$'À̰ųª `.'(½ÉÁö¾î ¸î¸î ½Ã½ºÅÛ¿¡¼´Â `_')ÀÏ ¼ö ÀÖ´Ù.
¸¸¾à joiner°¡ `_'À̶ó¸é ±×¶§ÀÇ Á¢µÎ¾î´Â ¹Ù·Î `_' ´ë½Å¿¡ `__static_'ÀÌ´Ù.
¿¹¸¦ µé¸é Foo::Bar::var
(¶Ç´Â Java ±¸¹®¿¡¼ Foo.Bar.var
)´Â `_Q23Foo3Bar$var'¶Ç´Â `_Q23Foo3Bar.var'(¶Ç´Â µå¹°°Ô `__static_Q23Foo3Bar_var')·Î ÀÎÄÚµùµÈ´Ù.
¸¸¾à Á¤Àû º¯¼öÀÇ À̸§ÀÌ Unicode escapesÀ» ÇÊ¿ä·Î ÇÑ´Ù¸é, Unicode indicator `U'´Â "joiner"¾Õ¿¡ ¿Â´Ù.
ÀÌ \u1234Foo::var\u3445
´Â _U8_1234FooU.var_3445
°¡ µÈ´Ù.
´ÙÀ½ Ưº°ÇÑ ¹®ÀÚµéÀº mangling¿¡¼ »ç¿ëµÈ´Ù:
bool
Çü°ú Java boolean
ÇüÀ» ÀÎÄÚµùÇÑ´Ù.
char
Çü°ú Java byte
ÇüÀ» ÀÎÄÚµùÇÑ´Ù.
const
À» °¡¸®Å°±âÀ§ÇÑ modifier.
¶ÇÇÑ const
¸â¹ö ÇÔ¼ö¸¦ °¡¸®Å°´Âµ¥ »ç¿ëµÈ´Ù.(¸Þ¼µåÀÇ Å¬·¡½ºÀÇ ÀÎÄÚµùÀ» ¿ì¼±ÇÏ´Â °æ¿ì¿¡)
double
ÇüÀ» ÀÎÄÚµùÇÑ´Ù.
...
¸¦ °¡¸®Å²´Ù.
float
ÇüÀ» ÀÎÄÚµùÇÑ´Ù.
int
ÇüÀ» ÀÎÄÚµùÇÑ´Ù.
intn_t
ÇüÅÂÀÇ typedef¸íÀ» ÀÎÄÚµùÇÑ´Ù. ¿©±â¼ nÀº ¾çÀÇ ½ÊÁø¼öÀÌ´Ù.
`I'´Â ´ÙÀ½¿¡ nÀÇ °ªÀ» ÀÎÄÚµùÇÏ´Â µÎÀÚ¸® 16Áø¼ö³ª ¹ØÁÙ»çÀÌ¿¡ ÀÓÀÇÀÇ 16Áø¼ö°¡ ¿Â´Ù.
¿¹¸¦ µé¸é, `I40'´Â int64_t
ÇüÀ» ÀÎÄÚµùÇÏ°í, `I_200_'´Â int512_t
ÇüÀ» ÀÎÄÚµùÇÑ´Ù.
long
ÇüÀ» ÀÎÄÚµùÇÑ´Ù.
long double
ÇüÀ» ÀÎÄÚµùÇÑ´Ù.
short
À» ÀÎÄÚµùÇÑ´Ù.
char
¿¡¼¸¸ »ç¿ëµÈ´Ù.
¶ÇÇÑ Á¤Àû ¸â¹ö ÇÔ¼ö¸¦ °¡¸®Å°±â À§ÇÑ modifier·Î½á »ç¿ëµÈ´Ù.
restrict
Çü qualifier.
void
ÇüÀ» ÀÎÄÚµùÇÑ´Ù.
volatile
Çü ¶Ç´Â ¸Þ¼µå¸¦ À§ÇÑ modifier.
wchar_t
Çü°ú Java char
ÇüÀ» ÀÎÄÚµùÇÑ´Ù.
long long
Çü°ú Java long
ÇüÀ» ÀÎÄÚµùÇÑ´Ù.
¹®ÀÚ `G', `M', `O', `p'´Â ¶ÇÇÑ ºÒºÐ¸íÇÑ ¸ñÀûÀ» À§ÇØ »ç¿ëµÇ´Â °Í °°´Ù.
óÀ½, ÀÌÀü, ´ÙÀ½, ¸¶Áö¸· Àý·Î °¡±â, ¸ñÂ÷.