使用consteval实现C++字符串加密时遭遇编译错误求助
问题:consteval字符串加密编译错误原因及解决方法
背景
原本用constexpr实现字符串加密,但部分字符串会在运行时执行,换成consteval强制编译时执行后,出现编译错误。
核心错误提示
Call to consteval function 'encrypt_string' is not a constant expression
pointer to subobject of temporary is not a constant expression
宏展开后的代码
decrypt_string(encrypt_string((char[]) { "s/x/apkpath/MainActivity" }, sizeof(char[]) { "s/x/apkpath/MainActivity" }),sizeof(char[]) { "s/x/apkpath/MainActivity" })
函数实现
consteval auto encrypt_string(char string[], uint32_t len) { for (int i = 0; i != len; i++) { string[i] = string[i] ^ keys_expr[i & 7]; } return string; } __attribute__((visibility("hidden"))) __attribute__((noinline)) __attribute__((optnone)) auto decrypt_string(char string[], int len) { for (int i = 0; i != len; i++) { string[i] = (string[i] & ~keys[i & 7]) | (~(string[i] & keys[i & 7]) & keys[i & 7]); //string[i] = string[i] ^ keys[i & 7]; } return string; }
编译配置(Android Studio + Clang)
在build.gradle中添加:
externalNativeBuild { cmake { cppFlags '-std=c++20' } }
完整编译错误信息
C:\Users\*\AppData\Local\Android\Sdk\ndk\25.1.8937393\toolchains\llvm\prebuilt\windows-x86_64\bin\clang++.exe --target=aarch64-none-linux-android24 --sysroot=C:/Users/*/AppData/Local/Android/Sdk/ndk/25.1.8937393/toolchains/llvm/prebuilt/windows-x86_64/sysroot -Dapkpath_EXPORTS -g -DANDROID -fdata-sections -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -D_FORTIFY_SOURCE=2 -Wformat -Werror=format-security -std=c++20 -fno-limit-debug-info -fPIC -MD -MT CMakeFiles/apkpath.dir/apkpath.cpp.o -MF CMakeFiles\apkpath.dir\apkpath.cpp.o.d -o CMakeFiles/apkpath.dir/apkpath.cpp.o -c C:/Users/*/AndroidStudioProjects/ApkPath/app/src/main/cpp/apkpath.cpp C:/Users/*/AndroidStudioProjects/ApkPath/app/src/main/cpp/apkpath.cpp:15:17: error: call to consteval function 'encrypt_string' is not a constant expression decrypt_string(encrypt_string((char[]) { "s/x/apkpath/MainActivity" }, sizeof(char[]) ^ C:/Users/*/AndroidStudioProjects/ApkPath/app/src/main/cpp/apkpath.cpp:15:17: note: pointer to subobject of temporary is not a constant expression C:/Users/*/AndroidStudioProjects/ApkPath/app/src/main/cpp/apkpath.cpp:15:32: note: temporary created here decrypt_string(encrypt_string((char[]) { "s/x/apkpath/MainActivity" }, sizeof(char[]) ^
错误原因
- 临时对象指针不符合常量表达式规则:
consteval要求所有操作必须是编译期可计算的常量表达式。你传入的(char[]) { "s/x/apkpath/MainActivity" }是临时数组,指向它的指针无法作为常量表达式——编译期无法确定临时对象的稳定地址。 - 字符串字面量的const属性冲突:字符串字面量本质是
const char[],强制转为char[]试图修改的操作,在consteval的常量表达式上下文中不被允许。
解决方法
方案1:编译期生成加密数组(推荐)
修改encrypt_string返回编译期加密后的数组,完全避免临时指针问题:
// 提前定义编译期密钥(必须是constexpr数组) constexpr uint8_t keys_expr[8] = {0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF}; template<size_t N> consteval auto encrypt_string(const char (&str)[N]) { std::array<char, N> result{}; for (size_t i = 0; i < N; ++i) { result[i] = str[i] ^ keys_expr[i & 7]; } return result; } // 解密函数简化(原写法等价于异或) __attribute__((visibility("hidden"))) __attribute__((noinline)) __attribute__((optnone)) const char* decrypt_string(char string[], int len) { for (int i = 0; i != len; ++i) { string[i] ^= keys[i & 7]; } return string; } // 宏简化写法 #define ENCRYPTED_STR(str) \ []() { \ auto encrypted_arr = encrypt_string(str); \ return decrypt_string(encrypted_arr.data(), encrypted_arr.size()); \ }()
encrypt_string在编译期生成加密后的std::array,运行时调用解密函数即可,完全符合consteval的编译期执行要求。
方案2:静态存储数组结合constexpr
如果坚持修改传入数组,需将字符串放在静态存储区,但consteval无法修改静态变量,因此改回constexpr并通过static_assert强制编译期执行:
constexpr auto encrypt_string(char string[], uint32_t len) { for (int i = 0; i != len; i++) { string[i] = string[i] ^ keys_expr[i & 7]; } return string; } // 宏写法 #define ENCRYPTED_STR(str) \ []() { \ static char arr[] = str; \ static_assert(encrypt_string(arr, sizeof(arr)) != nullptr, "Compile-time encryption failed"); \ return decrypt_string(arr, sizeof(arr)); \ }()
关键注意事项
consteval函数的所有操作必须是纯编译期的,不能涉及运行时对象(如临时指针、静态变量修改)。- 字符串字面量是
const的,不能直接在常量表达式中修改,必须复制到可修改的编译期数组中。 - 解密函数必须在运行时执行,需将编译期生成的加密数组传递给它,而非直接返回编译期指针。
内容的提问来源于stack exchange,提问作者na29
相关产品推荐
相关产品推荐

