【问题标题】:C Struct Compile ErrorC 结构编译错误
【发布时间】:2011-05-20 18:04:53
【问题描述】:

为什么下面的代码会产生编译时错误?我似乎不明白为什么类型不匹配。

typedef char f_string[MAX_CHARS+1] ;    /* string for each field */

/*
 * A parsed CSV line, with the number of fields and upto MAX_FIELDS themselves.
*/

typedef struct {
    int nfields ;               /* 0 => end of file */
    f_string field[MAX_FIELDS] ;        /* array of strings for fields */
} csv_line;

....

csv_line sut;
sut.field[0] = "Name, "; //Compile-time error.

错误是:

error: incompatible types in assignment

【问题讨论】:

    标签: c struct compiler-errors


    【解决方案1】:

    您正在尝试将const char * 分配给char[],这并不完全相同。如果您的 f_string 定义为

    ,这将起作用
    typedef const char * f_string;
    

    你在这里寻找的是

    strcpy ( sut.field[0], "Name, " );
    

    或者使用strncpy,这样你就可以指定目标缓冲区的大小..

    strncpy ( sut.field[0], "Name, ", MAX_CHARS )
    

    这将防止您超出缓冲区。

    【讨论】:

    • strncpy() 不是“安全的strcpy” - 它用于处理固定长度的字符串字段,这些字段不一定有空终止符。
    • 我不太确定您所说的“安全strcpy”是什么意思。 strncpy 允许您限制复制到目标缓冲区的字符数。如果将最大字符数设置为小于目标缓冲区的大小,并且源缓冲区包含的字符串大于目标缓冲区可以容纳的字符串,则不会超出它。正如我被提醒的那样,将会发生的是,您的目标缓冲区中不会有终止的 null ;必须处理这种情况并添加 null。
    • 对:如果源字符串太长,它不会添加终止'\0';如果源字符串很短,它将用'\0' 填充目标的其余部分(可能非常大)。由于必须处理前者,因此它并不是许多人似乎相信的“直接”替代strcpy()
    【解决方案2】:

    你需要使用类似的东西:

    strcpy( sut.field[0],"Name, ");
    

    除了在声明时作为初始化器之外,您不能像您尝试过的那样分配字符串。

    【讨论】:

      【解决方案3】:

      sut.field[0] 的类型是大小为 MAX_CHARS+1 的字符数组 - 您不能将字符串指针分配给字符数组。

      您要么需要将 csv_line::field 的类型更改为 const char*,要么只需将文字“Name,”的字符串复制到目标数组。

      请注意,strcpy()strncpy() 单独都是不安全的:第一个可能会溢出缓冲区,而第二个可能会使缓冲区没有 NUL 终止符。即使您“知道”有问题的字符串永远不会溢出,您也必须了解这两种情况。

      使用辅助函数安全地执行此操作:

      char * strncopy(char *dst, const char *src, int dstsize)
      {
          strncpy(dst, src, dstsize-1);
          dst[dstsize-1] = '\0';
      
          return dst;
      }
      

      然后:

      strncopy(sut.field[0], "Name, ", sizeof sut.field[0]);
      

      【讨论】:

      • 不需要做那个功能;它已经存在:strncpy 和 IIRC,strcpyn 在某些编译器上。
      • @Will 的代码strncopy 在内部使用strncpy。 OP 正在向strncpy 添加功能,以保证字符串始终以空值结尾。
      • 既然如此,那就完全不要使用strncpy,自己用一个简单的while循环,逐个字符地复制,记得在最后加上null。跨度>
      • @Will - 尽管指针错误很容易,尤其是一个错误,但您建议自己滚动而不是使用已知和测试过的函数?跨度>
      • 无论什么漂浮的船 - 我通常初始化我的缓冲区,以便它们以空值开头,然后strncpy,将其设置为比缓冲区大小小一作为要复制的最大字符数.有很多方法可以做到这一点;只是建议另一个。
      【解决方案4】:

      sut.field[0]char[MAX_CHARS+1]

      "Name, "const char*

      试试这个:

      strcpy(sut.field[0], "Name, ");
      

      【讨论】:

      • 感谢您的帮助。接受这个答案,因为它是最快的,很难在其他答案之间做出选择。
      【解决方案5】:

      sut.field[0] 的类型确实是char [MAX_CHARS+1]。但是,大多数其他答案的 "Name, " 类型是错误的 - 它实际上是 char [7] 类型(使用 sizeof "Name, " 进行简单演示)。

      尽管如此,您仍然不能直接将char [7] 分配给char [MAX_CHARS+1]。您甚至不能直接将 char [7] 分配给另一个 char [7]initialisation 以这种方式与 assignment 区别对待)。

      答案可能只是使用复制功能-例如,如果您确定MAX_CHARS >= 6,那么您可以使用strcpy()。如果您不能确定长度是否正确,那么您可以使用strncat() 作为截断字符串副本:

      sut.field[0][0] = '\0';
      strncat(sut.field[0], "Name, ", MAX_CHARS);
      

      (请注意,尽管有这个名字,strncpy()适合这个,事实上它很少是想要的功能)。


      值得指出的是,如果数组包含在struct 中,您可以间接分配数组(相同类型)。这意味着以下将起作用(如果您有 C99 编译器):

      typedef struct { char s[MAX_CHARS+1] } f_string;    /* string for each field */
      
      csv_line sut;
      sut.field[0] = (f_string){"Name, "};
      

      【讨论】:

      • +1 表示strncat。提醒strncpy在源大于目标时不会终止;也忘记了strncat 确实 以空值终止目标缓冲区。使用 C++ std::string 太久了,以至于我忘记了 C 字符串的一些细微差别。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-14
      相关资源
      最近更新 更多