【问题标题】:Can I get a char* out of either signed char* or unsigned char*?我可以从signed char* 或unsigned char* 中得到一个char* 吗?
【发布时间】:2015-11-05 02:11:58
【问题描述】:

我必须处理可能未签名的char 数组(因为它们来自 SCSI 数据块)。我想用这个函数来处理它们:

template <typename CharT, size_t Len>
std::string strFromArray(CharT (&src) [Len])
{     
    return std::string((typename boost::make_signed<CharT>::type *) src, Len);
}

错误在std::string构造函数调用中,它不能接受signed char/unsigned char,而只会接受char

我当然可以用(char *) src 替换强制转换,但是如果我传入非字符类型,我会丢失所有编译器错误。

我怎样才能写出它来构造所有“charry”类型的字符串?

【问题讨论】:

  • 传入非char类型真的很重要吗?
  • @M.M 我必须处理很多wchar_t 字符串,所以如果我误用它,我宁愿收到警告。
  • 既然您使用的是模板,为什么不使用 SFINAE?

标签: c++ string char unsigned


【解决方案1】:

只需将静态断言放入您的函数并稍作修改即可:

#include <string>

template <typename CharT, std::size_t Len>
std::string strFromArray(CharT (&src) [Len])
{
    // Anythig which looks like a char is considered a char.
    static_assert(sizeof(CharT) == sizeof(char), "Invalid Character Type");
    std::size_t n = Len;
    // Do not use a terminating zero (might be wrong if the source is no char 
    // literal, but an array of binary data.
    if( ! src[n-1])
        --n;
    return std::string(src, src + n);
}

int main()
{
    char c[3] = {};
    signed char sc[3] = {};
    unsigned char uc[3] = {};
    wchar_t wc[3] = {};
    strFromArray(c);
    strFromArray(sc);
    strFromArray(uc);
    // error: static assertion failed: Invalid Character Type
    // strFromArray(wc);
}

【讨论】:

  • 我觉得我比我发布的更喜欢这个:)
【解决方案2】:

我会尽可能简单,并使用:

#include <iostream>
#include <string>

namespace conv {
    template <size_t len>
    std::string strFromArray(const char(&arr)[len])
    {
        static_assert(len > 0, "don't use zero-sized arrays");
        return std::string(arr, len - 1);
    }

    template <size_t len>
    std::string strFromArray(const unsigned char(&arr)[len])
    {
        static_assert(len > 0, "don't use zero-sized arrays");
        return std::string((const char *)arr, len - 1);
    }
}

int main()
{
    const char charstr[] = "abcd";
    std::string str = conv::strFromArray(charstr);
    std::cout << str << std::endl;

    const unsigned char ucharstr[] = "efg";
    str = conv::strFromArray(ucharstr);
    std::cout << str << std::endl;

/*not possible:
    const wchar_t wcharstr[] = L"hijk";
    str = conv::strFromArray(wcharstr);
*/

}

Test it live

【讨论】:

  • 注意字符串长度! (例如,添加一些asserting 来查看问题。)但是保持简单是个好主意。真希望我能想到这一点。 ;-)
  • signed char 是另一种可能
  • @Cheersandhth.-Alf,是的,我明白你的意思。你的答案是正确的。我会改的。
  • @M.M 我必须承认我从未听说过或使用过signed char。但我的猜测是,它是关于总是签名的,所以我假设一个项目使用signed charchar,但不能同时使用两者?
  • 有时signed char 用于对变量进行签名很重要的情况。纯 char 可以由实现自行决定是否签名或未签名。不过,也许 OP 从来没有使用过signed char,所以他可以在没有案例的情况下使用它。
【解决方案3】:

假设转换为string 表示字节数组携带以空字符结尾的C 字符串(例如字符串文字):

#include <string>
#include <stddef.h>

namespace my {
    using std::string;
    using Size = ptrdiff_t;

    namespace detail {
        auto is_char_type( char const* ) -> bool;
        auto is_char_type( signed char const* ) -> bool;
        auto is_char_type( unsigned char const* ) -> bool;
    }  // namespace detail

    template< class Char, Size n >
    auto string_from( Char (&src) [n] )
        -> string
    {     
        (void) sizeof( detail::is_char_type( src ) );
        return string( src, src + n - 1 );
    }
}  // namespace my

auto main() -> int
{
    unsigned char const data[] = "Blah";
    auto const s = my::string_from( data );

#ifdef TEST_WCHAR
    wchar_t const wdata[] = L"Blah";
    auto const ungood_s = my::string_from( wdata );      // Doesn't compile.
#endif
}

如果这是关于任意二进制数据而不是字符串,则仅使用 src + n 而不是 src + n - 1

但是,对于二进制数据,您可能需要单独的长度,即不使用原始数组本身的长度。

【讨论】:

  • 我不知道 OP 是否希望它工作或失败 signed char;我认为值得一提的是这段代码是如何与它一起工作的。
  • 另外,它是否适用于非 const char data[100] = "blah"?它会以令人惊讶的方式工作吗?
  • 输入序列不兼容,但序列上的迭代器兼容。我不知道。谢谢。 (我希望它可以与 signed char 一起使用,并且确实如此)
  • 结束迭代器的 - 1 似乎不正确。
  • @FelixDombek:结束迭代器是正确的。 char 的数组,作为 C 字符串,是空终止的。你需要在最后去掉那个空值。顺便说一句,我个人只对我确定的事情投反对票。我从来没有对模糊的预感投反对票。此外,即使结束迭代器不正确,我也不会投反对票,而是发表评论。正如我在这里所做的 alain's answer 一样,它确实给了你不正确的字符串长度。这是思维错误或事实错误与简单的错字或忘记之间的区别。
猜你喜欢
  • 2012-09-27
  • 1970-01-01
  • 2017-03-27
  • 1970-01-01
  • 1970-01-01
  • 2023-02-10
  • 2011-07-02
  • 2012-01-13
  • 2013-02-11
相关资源
最近更新 更多