使用sprintf函数的附带效果

时间:2018-08-11 23:00:51

标签: c

当我使用sprintf函数以某种方式改变变量A的值时,会怎样?

#include <stdio.h>

int main(void) {

    short int A = 8000;

    char byte_1[2] /*0001 1111 01000 0000*/, total[4]; 
    sprintf(byte_1, "%i", A);
    printf("%s\n", byte_1);// displayed on the screen 8000
    printf("%i\n", A); // displayed on the screen 12336
}

4 个答案:

答案 0 :(得分:8)

(100, 200, 300, 400) 太短,无法用十进制表示byte_1的表示形式:它只能有1位数字和空终止符,而A没有此信息,因此它将尝试在sprintf数组的末尾进行写操作,从而导致未定义的行为。

  • byte_1增大为12个字节是一个好的开始。
  • byte_1本质上是不安全的。使用sprintf来防止缓冲区溢出:

    snprintf

以下是这种意外输出的可能解释:假设snprintf(byte_1, sizeof byte_1, "%i", A); 位于byte_1之前的内存中。 Asprintf的值转换为五个字符A'8''0''0''0' '\0'的值,并覆盖变量byte_1本身的值。当您以后用A打印A的值时,printf不再具有值A,而是8000 ...只是无限范围之一未定义行为的可能影响。

尝试使用此更正版本:

12336

答案 1 :(得分:3)

存储在A中的值的文本表示形式为”8000”-这是四个字符字符串终止符,因此byte_1必须为至少 5个字符宽。如果要byte_1存储任何无符号int的表示形式,则应使其更像12个字符宽:

char byte_1[12];

两个字符不足以存储字符串”8000”,因此当sprintf写入byte_1时,这些多余的字符很可能会覆盖A

还要注意,无符号int的正确转换说明符是%u,而不是%i。当尝试格式化设置了最高有效位的非常大的无符号值时,这将很重要。 %i将尝试将其格式化为负号。

修改

正如chrqlie所指出的,OP宣布Ashort int –由于某种原因,另一个答案已将其更改为unsigned int,并且一直困扰着我。严格来说,如果要带符号的十进制输出,则short int的正确转换说明符是%hd

为便于记录,以下是一些常见的转换说明符及其相关类型的列表:

Specifier        Argument type        Output
---------        -------------        ------
      i,d                  int        Signed decimal integer
        u         unsigned int        Unsigned decimal integer
      x,X         unsigned int        Unsigned hexadecimal integer
        o         unsigned int        Unsigned octal integer
        f        float, double        Signed decimal float
        s               char *        Text string
        c                 char        Single character
        p               void *        Pointer value, implementation-defined

对于shortlong类型,有一些长度修饰符:

Specifier        Argument type        Output
---------        -------------        ------
       hd                short        signed decimal integer
      hhd                 char        signed decimal integer
       ld                 long        signed decimal integer
      lld            long long        signed decimal integer

这些相同的修饰符可以应用于uxXo等。

答案 2 :(得分:0)

byte_1对于“ A”的四位数而言太小。它只有一个位数和空(\0)终止符的空间。如果您将byte_1做成5个字节的数组,每个数字1个位,空字节,则可以容纳“ A”。

#include <stdio.h>

int main(void) {

    unsigned int A = 8000;

    char byte_1[5], total[4]; 
    sprintf(byte_1, "%i", A);
    printf("%s\n", byte_1);
    printf("%i\n", A);

    return 0;
}

基本上,搞乱内存并试图将值放入对它们来说太小的变量是未定义的行为。这是合法的,但从客观上讲在C语言中是危险的,任何程序都不应像这样访问内存。

答案 3 :(得分:-5)

sprintf(byte_1, "%i", A);

格式说明符需要同意变量类型。

我建议进行以下更改:

sprintf(byte_1, "%c", A); printf("%c\n", byte_1);


编辑:因此,执行上述更改后的另一项更改是也更改A,使其与byte_1具有相同的类型。这将迫使您更改示例中的值以匹配char类型的范围。请注意,使用函数来保护您的溢出只是一个不好的解决方案。相反,作为此代码的设计师,您的责任是为该工作选择合适的工具。使用char变量时,需要使用类似于char的容器。整数,浮点数,字符串等也一样。如果您有1公斤的糖,则要使用1公斤的容器来容纳此数量。如您所见,您不会使用杯子(250g),因为杯子会溢出。在C中编码愉快!