公司动态
C++ 属性标记详解
C 匿名位域详解一、C 属性标记详解1、属性标记的语法2、常用标准属性3、 属性标记的作用4、编译器扩展属性5、属性标记的注意事项二、代码示例一、C 属性标记详解C 属性Attribute是自 C11 标准引入的一种标准化语法用于向编译器提供额外的语义信息辅助其进行优化、警告和代码检查。属性以[[...]]的形式出现可以作用于类型、函数、变量、语句等几乎所有的声明位置且不会改变程序的正常运行逻辑。1、属性标记的语法属性标记的基本语法为[[属性名]]或[[属性名(参数)]]可以叠加使用多个属性[[属性名]][[属性名(参数)]][[属性名1,属性名2]]// 同一位置叠加多个属性属性可以放置在声明之前也可以放置在声明之后如类型之后具体取决于属性所修饰的对象。C 标准库和编译器还允许使用带命名空间的属性例如[[gnu::always_inline]]以避免不同编译器之间的属性名冲突。2、常用标准属性[[noreturn]]标记函数不会返回帮助编译器优化并消除未定义行为警告。[[deprecated]]标记某个实体已废弃使用时会触发编译警告可附带替代方案说明。[[fallthrough]]用于switch语句中明确表示某个case分支有意不break避免编译器误报。[[nodiscard]]标记返回值不应被忽略若调用方丢弃返回值则产生警告。[[maybe_unused]]标记变量或参数可能未被使用抑制未使用警告。[[likely]]/[[unlikely]]C20标记分支执行的可能性辅助编译器优化分支预测。[[no_unique_address]]C20标记非静态数据成员可以与其他成员共享地址用于优化空类对象的内存占用。[[carries_dependency]]标记函数参数或返回值携带内存依赖序用于多线程与原子操作的优化场景。3、 属性标记的作用属性标记的核心价值在于在不改变程序语义的前提下为编译器提供更多上下文信息。例如[[nodiscard]]能有效防止开发者忽略错误码[[deprecated]]能平滑推进接口的迭代升级[[likely]]/[[unlikely]]能帮助编译器生成更高效的分支代码。合理使用属性标记可以显著提升代码的可读性、健壮性和可维护性。4、编译器扩展属性除了标准属性主流编译器还提供各自的扩展属性通常以命名空间前缀区分[[gnu::...]]GCC 与 Clang 的扩展属性如[[gnu::always_inline]]、[[gnu::hot]]。[[clang::...]]Clang 特有的扩展属性。[[msvc::...]]MSVC 特有的扩展属性。使用编译器扩展属性时建议通过宏进行封装以便在跨平台项目中优雅降级#ifdefined(__GNUC__)||defined(__clang__)#defineFORCE_INLINE[[gnu::always_inline]]inline#else#defineFORCE_INLINEinline#endif5、属性标记的注意事项属性标记不会改变程序的语义编译器可以选择忽略不认识的属性但会给出警告。属性标记的位置必须合法例如[[noreturn]]只能用于函数声明不能用于变量。不同编译器对扩展属性的支持程度不同跨平台代码应优先使用标准属性。属性标记不能用于修饰表达式只能修饰声明或语句。二、代码示例#includeiostream#includecstdint// 平台兼容MSVC没有 [[gnu::packed]]改用 #pragma pack#ifdefined(_MSC_VER)#definePACKED_BEGIN__pragma(pack(push,1))#definePACKED_END__pragma(pack(pop))#else#definePACKED_BEGIN#definePACKED_END#endif// [[nodiscard]] C17 [[nodiscard(请处理错误码不要忽略返回值)]]intdo_work(intval){returnval1;}enumclass[[nodiscard]]ErrorCode{OK0,FAIL1};ErrorCodeopen_device(){returnErrorCode::FAIL;}// [[maybe_unused]] C17 [[maybe_unused]]voiddebug_func(){}voidtest_maybe_unused([[maybe_unused]]intarg0,intarg1){[[maybe_unused]]intlocal_val100;std::coutarg1\n;}// [[deprecated]] C14 [[deprecated(old_func已废弃请使用 new_func())]]voidold_func(){std::coutold func\n;}voidnew_func(){std::coutnew func\n;}// [[fallthrough]] C17 voidtest_fallthrough(intv){switch(v){case1:std::coutcase 1\n;[[fallthrough]];case2:std::coutcase 2\n;break;case3:std::coutcase3\n;break;}}// [[likely]] [[unlikely]] C20 (MSVC部分版本忽略) inttest_likely_unlikely(intx){#ifdefined(_MSC_VER)// MSVC暂不支持标准属性直接去掉属性if(x0){returnx*2;}elseif(x-100){return0;}#elseif([[likely]]x0){returnx*2;}elseif([[unlikely]]x-100){return0;}#endifreturnx;}// [[no_unique_address]] C20 structEmptyTag{//空结构体};structMyObj{uint32_tid{};[[no_unique_address]]EmptyTag tag;};// packed 压缩结构体 跨平台 PACKED_BEGINstructPackedReg{uint8_ta;uint32_tb;uint16_tc;};PACKED_ENDintmain(){// nodiscardintretdo_work(10);(void)do_work(20);ErrorCode ecopen_device();// maybe_unusedtest_maybe_unused(0,666);debug_func();// deprecated// old_func(); //打开会编译警告new_func();// fallthroughtest_fallthrough(1);// likely/unlikelytest_likely_unlikely(5);// no_unique_addressstd::coutsizeof(EmptyTag) sizeof(EmptyTag)\n;std::coutsizeof(MyObj) sizeof(MyObj)\n;// packed structstd::coutsizeof(PackedReg) sizeof(PackedReg)\n;return0;}