【问题标题】:Why "const int" to "int" conversion works but "const char[]" to "char *" does not为什么“const int”到“int”转换有效,但“const char[]”到“char *”无效
【发布时间】:2015-01-05 06:38:46
【问题描述】:

这是我一直对 C++ 语言感兴趣的地方。随着“const”标识符的出现,它应该取代使用#define 语句来声明常量。但正如我所说的使用它们,我最终陷入了 const char 到 char 转换错误的疯狂。

最近,我说在类常量中做,就像在 Java 中做的一样。所以我决定声明这样的东西。

private: const static int NB_FIELD = 22;

这非常有效。返回 int 的函数可以毫无问题地返回“const int”。

但是现在如果我尝试对这样的字符串做同样的事情:

private: static const char ERRORSTR [ 6 ];

其中包含字符串“Error”,会产生类似此函数中的 const char 到 char 转换问题。

char* EnhancedSQLobject::get_SQLname ( int index )
{
   if ( index < p_nb_field && index >= 0 )
      return ( p_SQLfield_ptr [ index ] . SQLname)

   return ( ERRORSTR );

}

现在有人会说更改 const char* 的返回值,但我不能,因为如果索引有效,它将返回一个非常量变量,但如果索引无效,它将返回一个常量错误细绳。

所以我的选择是要么使错误字符串非常量,要么使用#define 语句创建一个常量。我记得很久以前试图将所有内容定义为 const char,但最终它在转换链中的其他地方爆炸了。让使用常规 char 变得更容易(String 类对我来说不是一个选项)

这简直太荒谬了,为什么要实现一个只适用于部分变量类型的功能。我想这与字符串实际上是字符表有关,因此它可能返回一个指针而不是一个值。

【问题讨论】:

  • "这太荒谬了,为什么要实现一个只对部分变量类型有效的功能。" - 实际上,这不是正在发生的事情。在一种情况下,您正在谈论将const int 转换为int,但在另一种情况下,您正在谈论将const char* 转换为char*,这增加了间接级别。
  • 您将非指针类型与指针类型进行比较。 T 不能与 T2 * 进行比较,假设 TT2 是基本类型。
  • 在一种情况下,int 被复制。另一种是复制指针,既然指向常量数据,为什么要转换呢?
  • 出错时返回 nullptr。问题已解决。 :-) 不管怎样,const 的主要用途不是替换defines 来定义常量。它的主要用途是保证函数不会修改调用者的参数副本(当通过引用或指针传递时)。
  • "您将非指针类型与指针类型进行比较。" - 和我想的一样。如果我对单个字符做同样的事情,那将不是问题。

标签: c++ char int type-conversion constants


【解决方案1】:

在一种情况下,您正在谈论将const int 转换为int,而在另一种情况下,您正在将const char* 转换为char*。这些确实是不同的情况,应该表现不同,因为后者添加了一个间接级别(指针)。您绝对可以将 const char 转换为 char,但这不是您正在做的事情。

考虑以下错误代码:

const int i = 50;
int j = i;
int* p = &i; // ERROR

我尝试做int j = i;,这很好。原始的i 对象仍然是const,而j 对象的值与i 相同。但是,如果我尝试执行int* p = &amp;i;,我们就会遇到问题。如果这可以编译,我们将有 p 指向一个 const int,即使它告诉我们它指向一个非 const int。这将允许我们通过指针 p 修改 const 对象 i - 这非常糟糕。

你也有同样的情况,只是chars。您的ERRORSTR 中的所有chars 都是const。然后您不能返回指向任何chars 的char*,因为那是在撒谎。指针不是指向非 const char,而是指向 const 字符。

ints 和 chars 在这方面的行为没有任何不同。

但是,我认为您只是因为界面设计不佳而陷入困境。为什么你的函数在找不到“SQLname”(不管是什么)时会返回一个特殊的字符串?例如,如果字符串“Error”实际上是一个有效的名称怎么办?函数的调用者如何区分?我认为如果你的函数不能完成get_SQLname 的动作(也就是说,它不能得到名字),它应该抛出一个异常。

除此之外,您应该使用 std::string 而不是 C 风格的 char*s。

【讨论】:

  • "例如,如果字符串 "Error" 实际上是一个有效的名称怎么办?" - 事实上,字符串不是由计算机解释的。只是如果我在屏幕或数据库中看到这个字符串,那么我就知道会发生错误。
  • "除此之外,您应该使用 std::string 而不是 C 风格的 char*s。" - 我对 Java 中的字符串类没有任何意见,但在 C++ 中我尽量避免它,因为我遇到了很多麻烦。事实上,我什至不使用动态分配,除非我真的非常需要它。为我节省了很多很难找到的问题和错误。在 Java 中,我不介意。
  • @larienna 嗯?您对std::string 有什么问题?您根本不应该使用 std::string 进行任何手动动态分配。
  • 不太记得了,很久以前用过。我什至不使用任何标准容器类。而且由于我正在使用 C 中的 allegro 进行编码,因此我无法通过 Iostream 字符串来显示它们。这是一个我正在尝试完成的旧程序,所以我需要继续使用旧方法。
【解决方案2】:

这两种转换之间存在差异。对于int

const int ci = 7;
int i = ci; // fine...
++i;        // ... because ci is still 7

但如果你能为char*做到这一点:

const char msg[] = "Hi";
char* p = msg; // not OK...
*p = 'B';      // ... because now msg = "Bi" 
               //     and it was supposed to be const!

与前者的实际等价的指针是:

char * const cc = someBuf();
char * c = cc; // this is totally OK
++c;           // ... because we're not modifying cc in any way

这是 const 指针和指向 const 的指针之间的区别。

【讨论】:

    【解决方案3】:

    您知道,使用 #define 不会像您预期的那样工作,至少如果您真正使用的是 C++ 而不是 C,则不会。

    在 C++ 中,字符串文字是 const,因此如果你声明:

    #define ERRORSTR "ERROR"
    

    而您尝试从get_SQLnamereturn ERRORSTR,如果您尝试修改返回的字符串,可能会导致未定义的行为。您的编译器很可能只是为此发出警告,因为字符串文字为 const 的事实在很久以前在 C++ 中并不总是如此。

    #include <iostream>
    
    #define BLAH "blah"
    
    char *foo() {
        return BLAH;
    }
    
    int main(int argc, char *argv[]) {
        std::cout << foo() << std::endl;
    }
    

    在我的编译器上,我看到以下警告:

    so.cpp:6:12: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
    

    现实情况是,将#define 用于常量,尤其是字符串常量正是出于这个原因是不安全的,因此应该避免。 const 通过编译器为您提供一定程度的安全性,如果编译器告诉您转换不安全,则该错误是有原因的,您应该尝试找出原因并解决问题而不是仅仅试图消除错误或找到其他一些解决方法。事实上,依赖 C 的行为通常是 C++ 中的代码异味,而依赖于 Java 等另一种语言的语义更糟糕。尽管在语法上相似,Java、C 和 C++ 在它们的实际语义上都彼此非常不同。您最好学习这些差异,而不是仅仅尝试将您所知道的知识从一种语言应用到另一种语言。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-03-30
      • 1970-01-01
      • 1970-01-01
      • 2023-03-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多