Abseil 매크로 — ABSL_HAVE_*·ABSL_ATTRIBUTE_*
한 줄 요약:
ABSL_HAVE_*는 컴파일러·플랫폼 기능의 존재를 감지하고,ABSL_ATTRIBUTE_*는 표준화되지 않은 attribute의 컴파일러별 차이를 흡수한다. Abseil의 모든 코드가 이 두 매크로 위에 서 있다.
#어떤 문제를 푸는가
C++의 portability는 표준만으로 부족하다. 같은 표준 버전이라도 컴파일러마다 지원 정도가 다르고, 비표준 attribute가 코드의 성능·정확성에 큰 영향을 준다.
세 가지 종류의 차이를 처리해야 한다.
- 표준 기능의 존재 감지 — C++17이라도
<filesystem>지원 여부가 컴파일러마다 다름. - 컴파일러별 builtin —
__builtin_expect,__builtin_unreachable은 GCC/Clang에만. - attribute의 syntax 차이 —
[[nodiscard]]는 C++17, MSVC의__declspec(...)은 별도.
Abseil은 이 셋을 매크로로 감싸 통일한다.
#ABSL_HAVE_* — 기능 감지
ABSL_HAVE_*는 컴파일 시점에 사용 가능한 기능을 알려준다.
#if defined(__cpp_lib_filesystem) #define ABSL_HAVE_STD_FILESYSTEM 1#endif
#if defined(__has_builtin) && __has_builtin(__builtin_expect) #define ABSL_HAVE_BUILTIN_EXPECT 1#endif
#if defined(__cpp_exceptions) && __cpp_exceptions #define ABSL_HAVE_EXCEPTIONS 1#endif
#if defined(__cpp_rtti) && __cpp_rtti #define ABSL_HAVE_RTTI 1#endif사용 패턴은 단순하다.
#include "absl/base/config.h"
void DoIO() {#ifdef ABSL_HAVE_STD_FILESYSTEM std::filesystem::path p = "/tmp/x";#else // POSIX fallback const char* p = "/tmp/x";#endif}#주요 ABSL_HAVE_* 목록
| 매크로 | 감지 대상 |
|---|---|
ABSL_HAVE_BUILTIN(x) | clang/GCC builtin 존재 |
ABSL_HAVE_FEATURE(x) | clang feature 존재 |
ABSL_HAVE_ATTRIBUTE(x) | attribute 존재 |
ABSL_HAVE_CPP_ATTRIBUTE(x) | [[attr]] 형태 존재 |
ABSL_HAVE_EXCEPTIONS | -fno-exceptions 여부 |
ABSL_HAVE_RTTI | -fno-rtti 여부 |
ABSL_HAVE_THREAD_LOCAL | TLS 지원 |
ABSL_HAVE_ALIAS_TEMPLATE_ARGUMENT_DEDUCTION | C++20 alias template CTAD |
ABSL_HAVE_STD_OPTIONAL | <optional> 사용 가능 |
ABSL_HAVE_STD_VARIANT | <variant> 사용 가능 |
ABSL_HAVE_STD_STRING_VIEW | <string_view> 사용 가능 |
#_has* 컴파일러 builtin 활용
ABSL_HAVE_BUILTIN, ABSL_HAVE_ATTRIBUTE는 GCC/Clang의 __has_builtin, __has_attribute를 감싼다.
#if defined(__has_builtin) #define ABSL_HAVE_BUILTIN(x) __has_builtin(x)#else #define ABSL_HAVE_BUILTIN(x) 0#endif
// 사용#if ABSL_HAVE_BUILTIN(__builtin_unreachable) [[noreturn]] inline void Unreachable() { __builtin_unreachable(); }#else [[noreturn]] inline void Unreachable() { std::abort(); }#endif이 패턴이 Abseil 전반에서 반복된다. “지원하면 빠른 경로, 없으면 안전한 fallback.”
#ABSL_ATTRIBUTE_* — attribute 추상화
C++ attribute는 컴파일러마다 syntax가 다르다.
// 표준 C++11+[[noreturn]] void Die();
// GCC/Clang 확장__attribute__((noinline)) void Foo();
// MSVC 확장__declspec(noinline) void Bar();Abseil은 이런 차이를 매크로로 흡수한다.
// absl/base/attributes.h에서 발췌
#if ABSL_HAVE_ATTRIBUTE(noinline) || (defined(__GNUC__) && !defined(__clang__)) #define ABSL_ATTRIBUTE_NOINLINE __attribute__((noinline))#elif defined(_MSC_VER) #define ABSL_ATTRIBUTE_NOINLINE __declspec(noinline)#else #define ABSL_ATTRIBUTE_NOINLINE#endif
ABSL_ATTRIBUTE_NOINLINE void SlowPath();#주요 ABSL_ATTRIBUTE_*
| 매크로 | 의미 |
|---|---|
ABSL_ATTRIBUTE_NOINLINE | 인라인 금지 |
ABSL_ATTRIBUTE_ALWAYS_INLINE | 강제 인라인 |
ABSL_ATTRIBUTE_COLD | 거의 호출되지 않는 함수 (저속 경로) |
ABSL_ATTRIBUTE_HOT | 자주 호출되는 함수 |
ABSL_ATTRIBUTE_NORETURN | 돌아오지 않는 함수 |
ABSL_ATTRIBUTE_UNUSED | 사용되지 않아도 경고 안 함 |
ABSL_ATTRIBUTE_PACKED | struct padding 제거 |
ABSL_ATTRIBUTE_WEAK | weak symbol |
ABSL_ATTRIBUTE_LIFETIME_BOUND | 인자 lifetime이 반환값을 결정 |
ABSL_ATTRIBUTE_TRIVIAL_ABI | clang의 trivial_abi |
ABSL_ATTRIBUTE_REINITIALIZES | 객체가 재초기화되었음을 분석기에 알림 |
#LIFETIME_BOUND — 잘 알려지지 않은 중요한 도구
ABSL_ATTRIBUTE_LIFETIME_BOUND는 clang에서 dangling reference를 컴파일 시점에 잡아준다.
#include "absl/base/attributes.h"
class Person {public: const std::string& name() const ABSL_ATTRIBUTE_LIFETIME_BOUND { return name_; }private: std::string name_;};
// 위험한 사용 — clang이 경고const std::string& bad = Person().name();// warning: returning reference to local temporarystring_view, Span 같이 비소유 타입을 반환하는 함수에 붙이는 것이 권장된다. absl::string_view 자체가 모든 const string 반환 함수에 이걸 붙이고 있다.
#TRIVIAL_ABI — pass-by-value 최적화
ABSL_ATTRIBUTE_TRIVIAL_ABI는 destructor가 non-trivial한 타입이라도 ABI 관점에서 trivial로 다루도록 한다.
class ABSL_ATTRIBUTE_TRIVIAL_ABI MyHandle {public: ~MyHandle() { Release(); } // ...private: int fd_;};
void Process(MyHandle h);// MyHandle이 register로 전달될 수 있음 — 호출 비용 감소표준 ABI에서는 non-trivial destructor가 있으면 무조건 메모리로 전달된다. trivial_abi는 이 제약을 우회한다. clang에서만 동작하고, ABI break를 동반하므로 신중히 써야 한다.
#ABSL_PREDICT_*, ABSL_FALLTHROUGH_INTENDED
비슷한 카테고리에 속하는 매크로들.
// branch hintif (ABSL_PREDICT_FALSE(error_occurred)) { HandleError();}
// switch fall-through 의도 표시switch (x) { case 1: DoOne(); ABSL_FALLTHROUGH_INTENDED; case 2: DoTwo(); break;}ABSL_PREDICT_*는 Part 2-02에서 따로 다룬다.
#ABSL_DEPRECATED — 안전한 deprecation
ABSL_DEPRECATED는 컴파일러의 deprecation attribute를 감싼다.
#if ABSL_HAVE_CPP_ATTRIBUTE(deprecated) #define ABSL_DEPRECATED(msg) [[deprecated(msg)]]#elif defined(__GNUC__) #define ABSL_DEPRECATED(msg) __attribute__((deprecated(msg)))#else #define ABSL_DEPRECATED(msg)#endif
ABSL_DEPRECATED("Use NewAPI() instead") void OldAPI();deprecation message는 사용자가 마이그레이션 경로를 알 수 있도록 구체적으로 쓴다. “deprecated” 한 단어만 쓰는 것은 안티패턴.
#코드 리뷰 포인트
// 회피 — 컴파일러별 attribute를 직접 사용__attribute__((noinline)) void SlowPath();// MSVC에서 컴파일 안 됨.
// Good — Abseil 매크로ABSL_ATTRIBUTE_NOINLINE void SlowPath();// 회피 — __has_builtin을 직접 사용#if __has_builtin(__builtin_expect)// 정의되지 않은 컴파일러에서 syntax error.
// Good#if ABSL_HAVE_BUILTIN(__builtin_expect)// 회피 — string_view 반환에 LIFETIME_BOUND 누락absl::string_view GetName() const { return name_; }
// Goodabsl::string_view GetName() const ABSL_ATTRIBUTE_LIFETIME_BOUND { return name_;}리뷰에서 봐야 할 것:
- 컴파일러별 분기를 직접 쓰는가 — Abseil 매크로로 감싸야 함.
- 비소유 타입을 반환하는데 LIFETIME_BOUND 없는가 — clang에서 미리 잡을 수 있는 버그.
- deprecation message가 마이그레이션 경로를 알려주는가.
#자주 보는 안티패턴
// 회피 — ABSL_HAVE_*를 그냥 무시std::optional<int> Find(int key); // C++17 가정// C++14 빌드에서 깨짐.
// Good#ifdef ABSL_HAVE_STD_OPTIONAL std::optional<int> Find(int key);#else absl::optional<int> Find(int key);#endif// 또는 처음부터 absl::optional만 쓰고 마이그레이션은 한 번에// 회피 — ALWAYS_INLINE을 무분별하게ABSL_ATTRIBUTE_ALWAYS_INLINE void HelperA();ABSL_ATTRIBUTE_ALWAYS_INLINE void HelperB();ABSL_ATTRIBUTE_ALWAYS_INLINE void HelperC();// 코드 크기 증가, instruction cache 압박.// 측정 없이 ALWAYS_INLINE을 붙이는 것은 보통 손해.
// Good — hot path만 측정해서 선택적으로#정리
ABSL_HAVE_*는 컴파일러·플랫폼 기능 존재 감지.ABSL_ATTRIBUTE_*는 컴파일러별 attribute 차이 흡수.LIFETIME_BOUND,TRIVIAL_ABI같은 잘 안 알려진 매크로가 안전성·성능에 큰 도움.- 컴파일러별 분기를 직접 쓰지 말고 Abseil 매크로로 감쌀 것.
ALWAYS_INLINE은 측정 후에만.
#다음 편
Part 2-02에서 ABSL_PREDICT_TRUE / ABSL_PREDICT_FALSE를 본다. branch hint가 성능에 실제로 얼마나 영향을 주는지, modern CPU에서 어디까지 의미가 있는지 살핀다.
#관련 항목
Abseil Code Review · 7 of 79
- 1 Abseil Code Review — Google production-grade C++ 라이브러리 분석
- 2 Abseil 개요 — Google이 std를 보완한 이유
- 3 Abseil 설계 철학 — std 호환과 추가 기능의 균형
- 4 Abseil 빌드와 의존성 — Bazel vs CMake
- 5 Abseil LTS vs HEAD 릴리스 모델 분석
- 6 Abseil Versioning과 ABI 호환성 정책
- 7 Abseil 매크로 — ABSL_HAVE_*·ABSL_ATTRIBUTE_*
- 8 Abseil ABSL_PREDICT_TRUE/FALSE — branch hint
- 9 absl::LogSeverity — 로그 레벨 타입
- 10 Abseil type_traits — negation·conjunction·void_t
- 11 Abseil Conformance·Policy 분석
- 12 Abseil Memory utilities 분석
- 13 Abseil raw_logging — heap-free 로깅
- 14 Abseil thread_annotations — clang TSA 통합
- 15 absl::Status — exception-free error handling
- 16 absl::StatusOr<T> — 값 또는 에러
- 17 absl status_macros — ASSIGN_OR_RETURN·RETURN_IF_ERROR
- 18 absl::Status payload — 구조화된 에러 컨텍스트
- 19 absl::Status ↔ exception 변환 패턴
- 20 absl::string_view — non-owning 문자열 참조
- 21 absl::string_view 함정 — dangling·c_str·임시 객체
- 22 absl::StrCat — 가변 인자 문자열 연결과 AlphaNum
- 23 absl::StrSplit — Delimiter·Predicate·컨테이너 변환
- 24 absl::StrJoin — 컨테이너 결합과 Formatter
- 25 absl::StrFormat — type-safe printf·FormatSpec
- 26 Abseil ASCII 함수 — locale-free 분류·대소문자 변환
- 27 Abseil Escape — CEscape·HexEscape·Base64
- 28 absl::flat_hash_map — Swiss Table 기반 hash map
- 29 absl::flat_hash_set — set 버전 Swiss Table
- 30 absl::node_hash_map — stable pointer가 필요할 때
- 31 absl::btree_map — sorted·cache-friendly B-tree
- 32 absl::FixedArray — 런타임 크기 stack 배열
- 33 absl::InlinedVector — small buffer optimization
- 34 Abseil Swiss Table internals — control byte·SIMD probing
- 35 absl::Mutex — reader-writer·fairness·deadlock 검출
- 36 absl::Mutex Conditional Critical Section — Await로 cv 없애기
- 37 absl::Notification — once-only signal
- 38 absl::BlockingCounter·Barrier — 다중 thread 조율
- 39 absl::Mutex annotations — clang thread-safety로 race를 컴파일 타임에
- 40 absl::Time·Duration 분석 — 단단한 type
- 41 absl::Time Format·Parse
- 42 absl::CivilTime 분석
- 43 absl::time_zone 분석
- 44 absl::Time mocking — 테스트 친화 시간
- 45 absl::BitGen — 모던 난수 생성기
- 46 Abseil Random Distributions — Uniform·Exponential
- 47 Abseil Mocking Random — 테스트 결정성
- 48 Abseil Random Seeding·Entropy
- 49 absl::int128·uint128 분석
- 50 absl::bits — popcount·countl_zero
- 51 absl::optional vs std::optional
- 52 absl::variant 분석
- 53 absl::span 분석
- 54 absl::any 분석
- 55 absl::compare — three-way 비교
- 56 Abseil utility — apply·in_place
- 57 Abseil AbslHashValue 분석
- 58 Abseil HashState chaining
- 59 Abseil Custom hashable 구현
- 60 Abseil LOG·VLOG·CHECK 분석
- 61 Abseil LogSink 분석
- 62 Abseil LogEntry·structured logging
- 63 Abseil Stack trace·failure_signal_handler
- 64 ABSL_FLAG 정의 분석
- 65 Abseil ParseCommandLine 동작
- 66 Abseil Flag introspection·validation
- 67 Google 스타일의 Abseil 사용 패턴
- 68 Abseil 자주 보는 anti-pattern
- 69 std → absl 마이그레이션 전략
- 70 absl::Cleanup — 함수 종료 시 실행 보장
- 71 Abseil algorithm container 확장 — c_sort·c_find_if·c_count_if
- 72 absl::function_ref와 any_invocable — 함수 객체 전달의 두 축
- 73 absl::bind_front와 Overload — 함수 객체 보조 도구
- 74 absl::Cord — 분산 시스템용 대용량 문자열
- 75 absl::from_chars·SimpleAtoi — 빠른 숫자 변환
- 76 absl::Cord vs std::string — 선택 기준과 메모리 프로파일
- 77 absl::GetStackTrace와 Symbolize — crash 시 readable stack
- 78 absl::ComputeCrc32c — 하드웨어 가속 체크섬
- 79 absl::PeriodicSampler — 적응형 샘플링·jitter 회피
관련 글
absl status_macros — ASSIGN_OR_RETURN·RETURN_IF_ERROR
Part 3-03: RETURN_IF_ERROR와 ASSIGN_OR_RETURN — 에러 전파를 한 줄로. 매크로 expansion 분석과 안전한 사용법.
같은 시리즈에서 이어 읽기
Abseil raw_logging — heap-free 로깅
Part 2-07: raw_logging — heap, exception, mutex 없이 동작하는 로깅. signal handler, ASan early init, OOM 경로.
같은 시리즈에서 이어 읽기
Abseil Memory utilities 분석
Part 2-06: absl::memory — make_unique polyfill, allocator_traits, RawPtr, uninitialized helpers.
같은 시리즈에서 이어 읽기
이 글을 참조하는 글 (7)
- Abseil thread_annotations — clang TSA 통합 — Abseil Code Review
- Abseil Memory utilities 분석 — Abseil Code Review
- Abseil Conformance·Policy 분석 — Abseil Code Review
- Abseil type_traits — negation·conjunction·void_t — Abseil Code Review
- absl::LogSeverity — 로그 레벨 타입 — Abseil Code Review
- Abseil ABSL_PREDICT_TRUE/FALSE — branch hint — Abseil Code Review
- Abseil Versioning과 ABI 호환성 정책 — Abseil Code Review