【问题标题】:printf and custom classprintf 和自定义类
【发布时间】:2012-08-22 09:01:42
【问题描述】:

我有自己的代表自定义字符串类的类。我正在使用 VS2012RC。我已经重载了我的类 CustomString 的一些运算符。

这里有一些代码:

CustomString::CustomString(string setstr)
{           
    str = setstr;
}

CustomString::operator const char *()
{   
    return (this->str.c_str());
}

CustomString &CustomString::operator = (char *setstr)
{
    str = setstr;
    return *this;
}

我可以定义我的对象并像这样使用它:

CustomString str = "Test string";

我可以将结果打印为:

printf(str);

printf((string)(str).c_str());

printf((string)(str).data());

printf("%s\n",(string)(str).c_str());

printf("%s\n",(string)(str).data());

而且没有任何错误。

但如果我这样使用它:

printf("%s\n", str);

msvcr110d.dll中有异常(内存访问出错)

为什么printf(str)可以,printf("%s\n",str)不行?

如何修改我的代码以使用 printf("%s\n",str)

...

经过几个小时的谷歌搜索,我发现显式转换 (string)、static_cast (str) 和 _str() 方法都添加了一个以 null 结尾的字符:'\0';

我已将代码修改为:

printf("%s\n",str + '\0');

成功了!

有什么方法可以修改我的自定义构造函数以添加一个以空字符结尾的字符串并传递一个以空字符结尾的正确值以使以下代码正常工作:

printf("%s\n",str);

【问题讨论】:

  • 您使用的修改完全靠运气。在 ... 中传递类对象会导致未定义的行为。

标签: c++ printing visual-studio-2012


【解决方案1】:

你不能(至少不能以便携的方式)。 printf 查看作为参数传递的对象,并将其视为 %s,它是一个 char 数组。您遇到未定义的行为。此外,传递给printf 的参数可以说是无类型的。

为什么 printf(str) 没问题?

因为第一个参数是类型,并且是const char*。隐式转换是通过您的运算符进行的。其余参数的行为不同。

我会改用cout,并重载operator << (ostream&, const CustomString&)

不要这样做:

我说你不​​能,以便携的方式。对于像

这样的课程
class CustomString
{
   char* str;
   //...
};

这可能会起作用,因为类在内存中的表示方式。但是,同样,它仍然是未定义的行为。

【讨论】:

  • 您使用char* 的示例不正确。错误是一样的。
  • @user1616375 我告诉过你不要这样做!
  • 好的,你能解释一下吗:我试过printf("%s\n",str + '\0');,没关系。有什么方法可以修改我的自定义构造函数以添加以空字符结尾的字符串并使用以空字符结尾的字符传递正确的值?这是正确的方法吗?
  • @user1616375 确定。这是一个分号。
  • @user1616375 我刚刚阅读了您对问题的编辑。不要这样做。找到合适的方法。那是未定义的行为。它可能并不总是有效,它可能会崩溃。
【解决方案2】:

不要使用printf,它比 C++ 更像 C。相反,请使用iostreams,它为您提供了一种工具来格式化您自己的自定义类并将其发送到文件或标准输出。

这是一个可能适合您的快速(未经测试)示例:

std::ostream& operator<< (std::ostream &os, const CustomString& str)
{ 
    os << str.data();
    return os; 
} 

然后你会通过执行类似的操作将自定义字符串打印到标准输出

CustomString str;
// put some text in the custom string, then:
std::cout << str << std::endl;

【讨论】:

    【解决方案3】:

    printf 定义为

    int printf(char const *fmt, ...)
    

    将类或结构传递给 ... 参数列表具有未定义的行为,可能会工作或崩溃,或者只是随机做一些事情(我已经看到了所有 3 个),具体取决于类和编译器。

    printf(str)
    

    需要一个 char *,编译器发现你有一个合适的转换操作符,所以它调用它。请注意,这是非常狡猾的,因为您不知道 str 中是否可能包含 %。

    所以,你确实想要printf("%s", str),但正如你所说,那是行不通的。一些编译器会给你一个警告(尽管在我看来,由 gcc 产生的“警告:这将崩溃”并不是经过深思熟虑的),所以你必须强制它被强制转换为字符串。因此,您最好的解决方案是自己显式转换它,

    printf("%s", static_cast<char const *>(str));
    

    我不确定您所获得的所有示例需要多少代码,因为其中大多数将涉及从您的自定义字符串构造一个 std::string,然后输出它,然后删除 std ::字符串。

    【讨论】:

      【解决方案4】:

      您必须使用printf("%s\n", str.c_str());%s 需要一个 char 数组,而你给了它一个 CustomString 对象,这是不同的东西。您必须通过调用c_str() 函数从字符串中获取字符数组。

      【讨论】:

        猜你喜欢
        • 2012-03-04
        • 2013-03-03
        • 2019-09-18
        • 1970-01-01
        • 2013-08-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-02-21
        相关资源
        最近更新 更多