C字符串字面值处理

3
以下代码有什么问题导致程序崩溃并出现分段错误?我正在使用gcc。
uint8_t result = 1      

InsertRow("Name","Details of work",result);     

void InsertRow(char *Name, char *Description,uint8_t Result)   
{  
   char Buffer[500];  

   if(Result==1)   
      sprintf(Buffer,"<tr><td>%s </td> <td> %s </td> <td>  %s </td></tr>",Name,Description,Result);   
} 

1
考虑使用 snprintf 来防止缓冲区溢出。 - aschepler
3个回答

7
您正在使用%s格式说明符来处理类型为uint8_t的参数,应该使用%u,并将值转换为unsigned int以匹配。这样可以避免您关心确切的类型并调整格式说明符(如评论者建议的那样)。
此外,我们很难知道缓冲区是否足够大。如果有的话,您可以使用snprintf()来避免这种情况。

1
对于 uint8_t,应该使用 PRIu8 格式,%hhu 也可能是正确的选择。%u 是用于 unsigned int 的格式。 - Daniel Fischer
@Daniel:虽然uint8_t在变长参数中保证被提升为unsigned int,所以%u可以打印它。但我同意最好使用格式宏而不是试图解决这个问题。 - Steve Jessop
1
据我理解,整数提升规则是这样的:“如果一个int类型可以表示原始类型的所有值(对于位域来说受宽度限制),那么该值将被转换为int类型”,即被提升为int类型。因此从技术上讲,这可能会导致未定义行为,但我认为在任何实现中都不会出现意外情况。 - Daniel Fischer
@Daniel:好的,va_arg 中有一个特殊情况,即“一个类型是有符号整数类型,另一个类型是相应的无符号整数类型,并且该值在两种类型中都可以表示”,这种情况是可以使用 %u 的。但是我已经犯了一个错误试图证明它是正确的,这表明我不应该支持它 :-) 我记得 printf 风格的函数比 varargs 要求更严格的参数限制,所以你可能是对的,即使很难想象实现如何做到除了工作之外的其他事情。 - Steve Jessop
@SteveJessop 啊,那可能会使它成为定义行为。虽然我不确定,但法律术语并不是我的第一语言。工作,无论是定义还是未定义的行为,它几乎肯定会工作。 - Daniel Fischer
我曾经见过整数提升在printf中引起问题的唯一情况是当你将有符号整数提升为你认为是无符号格式的类型(即16进制或八进制),并且它进行了符号扩展。例如:int8_t x = 0xFF; uint8_t y = 0xFF; printf("%x %x\n", x, y); 就类型安全性而言(即不会导致segfaults),使用-Wall编译时,gcc非常擅长在您提供任何*printf函数错误参数时发出警告。 - Brian McFarland

1

这里

sprintf(Buffer,"<tr><td>%s </td> <td> %s </td> <td>  %s </td></tr>",Name,Description,Result);    

您正在将类型为uint8_tResult作为指向字符数组的指针传递

这意味着整数值将被解释为指针,最有可能指向您无法访问的内存--因此会出现段错误。您需要用适当的格式标志替换第三个%s,以将该值打印为整数

注意:在这种情况下不要直接使用%d,因为您的uint8_t类型不能保证与int大小相同(很可能不是)。如果您首先将Result的值强制转换为int(int)Result),则可以使用%d


0

结果不是char*,你可能想要使用%d


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接