在编译时收集所有静态C字符串的地址

时间:2018-05-23 13:06:30

标签: c++ linux g++ c++17

假设我有一个类似

的功能
void foo(const char* bar, ...)

它已被多个地方召集。

是否可以在main()中收集编译时已知的所有静态字符串的地址?

例如,foo("abc"),我希望main()能够获取"abc"的地址。如果有人拨打foo(someVariable),则someVariable的地址可能不知道,因此可以忽略。

有可能吗?

2 个答案:

答案 0 :(得分:1)

  

是否可以在main()中收集编译时已知的所有静态字符串的地址?

在编译时,来自其他翻译单元的字符串不可用。

您可以使用readelf -W -p .rodata <executable>命令从可执行文件或共享库中转储字符串文字。

答案 1 :(得分:1)

如果您同意使用注册,则可能会执行类似

的操作
// Would contain each registered string.
std::vector<const char*>& registered_vector()
{
    static std::vector<const char*> v;
    return v;
}

bool Register(const char* s)
{
    registered_vector().push_back(s);
    return true;
}

// Class which holds the unique pointer as buffer.
template <typename Char, Char... Cs>
struct static_string
{
    static constexpr Char s[] = {Cs..., 0};
};

template <typename Char, Char... Cs>
constexpr Char static_string<Char, Cs...>::s[];

// string literal operator templates are a GNU extension
// MACRO can replace the operator to avoid that extension.
template <typename Char, Char... Cs>
static_string<Char, Cs...> operator ""_ss()
{
    static_string<Char, Cs...> res;
    static const bool dummy = Register(res.s); // Register only once :-)
    static_cast<void>(dummy); // Avoid warning for unused variable
    return res;
}

现在,测试一下:

int main() {
    "Hello"_ss;
    "World"_ss;
    "Hello"_ss;
    "Hi"_ss;
    "42"_ss;

    for (const auto s : registered_vector()) {
        std::cout << s << std::endl;
    }
}

Demo