代码之家  ›  专栏  ›  技术社区  ›  pm100

c中字符串(不是std::string)常量的正确用法++

  •  3
  • pm100  · 技术社区  · 14 年前

    刚才我问过std::string常量 correct idiom for std::string constants?

    我从中得到的是 使用std::string常量,但使用char string常量。所以最好的成语是什么

    #define FOO "foo"
    
    const char * const FOO = "foo";
    
    const char FOO[] = "foo";
    

    • 在编译时获取长度。1&3但是 不是2(sizeof对2不起作用)
    • 可以包含在不带链接器的.h中 抱怨。全部(我想)
    • 输出。取决于编译器

    所以看起来3是最好的,但是scott meyers说使用2(有效的c++项目1)

    答案摘要

    1. 使用非常复杂的模板代码
    2. 使用#3

    模板代码看起来有点过头了。所以现在我用3;

    但是我会重新考虑模板代码,宏化版本让它看起来很酷;但是我不喜欢它不可移植的事实(谁知道呢,也许gcc也会认为它是错的)

    5 回复  |  直到 7 年前
        1
  •  0
  •   André Caron    14 年前

    你想要的特征是矛盾的。

    1. 在头文件中定义
    2. 跨编译单元的单个副本

    static 或者把它放在一个未命名的名称空间中。但是,这将导致每个编译单元中都有一个定义,这与(3)相反。

    要获得(2)和(3),需要将变量声明为 extern ,但这样你就得不到(1)。

    现在,如果你的链接器是智能的,它可能会优化掉多个副本,但我不确定标准是否允许它。。。

    我推荐 const char FOO[] = "foo"; 在未命名的命名空间中声明的语法或 如果需要在特定的命名空间中找到它。如果绳子很大,我就要 外部

        2
  •  4
  •   Cheers and hth. - Alf    14 年前

    对于你想要的功能。。。

    • 在编译时获取长度,
    • 可以包含在.h中而无需链接器抱怨,

    ... 你可以使用 模板常量习语 ,就像

    template< class Dummy >
    struct Foo_
    {
        static char const s[];
    };
    
    template< class Dummy >
    char const Foo_<Dummy>::s[] = "Blah blah";
    
    typedef Foo_<void> Foo;    // Now you can refer to Foo:s
    
    
    #include <iostream>
    using namespace std;
    int main()
    {
        cout << sizeof( Foo::s ) << " bytes: \"" << Foo::s << "\"\n";
    }
    

    可以用宏包装生成。

    然而,据我所知,唯一实用的工具是支持char/wchar_t-agnostic代码,因此痛苦可能大于收获。

    编辑
    MSVC 7.1到10.0版本不正确,不接受 sizeof

    #include <stddef.h>
    
    typedef ptrdiff_t   Size;
    
    // Substitute a more general countOf
    template< Size n >
    struct SizedBuf { char sizer[n]; };
    
    template< class Type, Size n >
    SizedBuf< n > countOf_( Type (&)[n] ) { return n; }
    
    #define COUNT_OF( array ) sizeof( countOf_( array ).sizer )
    
    #define DEF_STRING( name, value )                               \
        template< class >                                           \
        struct name##_constant_                                     \
        {                                                           \
            static char const str[];                                \
            static Size const length    = COUNT_OF( value ) - 1;    \
        };                                                          \
                                                                    \
        template< class Type >                                      \
        char const name##_constant_< Type >::str[] = value;         \
                                                                    \
        template< class Type >                                      \
        Size const name##_constant_< Type >::length;                \
                                                                    \
        typedef name##_constant_<void>  name;
    
    
    DEF_STRING( a, "Argh, MSVC!" )
    DEF_STRING( b, "Blah blah" )
    DEF_STRING( c, "Currently there's no 'inline' for data in C++." )
    
    
    #include <iostream>
    
    template< char const* s >
    void foo() { std::cout << "foo() says: " << s << std::endl; }
    
    int main()
    {
        using namespace std;
    
        int const x[a::length] = {};    // Showing off compile time constant.
        foo<a::str>();                  // Showing off external linkage.
    
        cout << a::length << " characters: \"" << a::str << "\"." << endl;
    }
    

    干杯。,

        3
  •  0
  •   Diego Sevilla    14 年前

    // .h
    extern const char*const STR;
    
    // .cpp
    const  char*const STR = "abc";
    

    唯一的缺点是,在运行时没有长度,在我看来,这并不是转向其他选项的真正原因。如果有多个字符串,则始终可以有一组整数常量(或 #define s) 指定每个字符串的长度,例如 STR_LEN . 如果你有很多,你也不会在手边写,然后你可以自动生成 ..._LEN

        4
  •  0
  •   Greg Domjan    14 年前

    我认为你从上一个问题中去掉了错误的想法。
    字符串往往很稀疏,不适合查找,请使用数字。

    在.h中声明和在.cpp中定义存储之间似乎仍然没有区别,因此避免了多个副本。即使您有多个副本(具有不同的常量名称),您仍然会有您在上一个问题中提到的问题。

    避免这种情况的唯一方法是将常量带入与当前静态模块级别相同的范围。

    把所有相关的东西放在一个班里!

        5
  •  0
  •   GManNickG    14 年前

    这只是阿尔夫的回答:

    #include <iostream>
    
    #define string_constant(pName, pLiteral)                    \
            template <typename = void>                          \
            struct pName##_detail                               \
            {                                                   \
                static const char value[];                      \
            };                                                  \
                                                                \
            template <typename T>                               \
            const char pName##_detail<T>::value[] = pLiteral;   \
                                                                \
            typedef pName##_detail<> pName
    
    string_constant(my_constant, "this is a literal");
    
    int main()
    {
        std::cout << my_constant::value << std::endl;
        std::cout << sizeof my_constant::value << std::endl;
    }
    

    codepad . 在VS2010中似乎不起作用。:/