#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void main ()
{
char *imsi;
unsigned int i;
int val;
char *dest;
imsi = "405750111";
strncpy(dest,imsi,5);
printf("%s",dest);
/* i = 10; */
}
在上面的代码中,如上所述对 i = 10 分配进行了注释,代码工作正常,没有错误。当包含分配以进行编译时,错误 (分段错误) 发生在 strncpy(dest,imsi,5);
通过避免优化变量 i (即 volatile int i; ),错误被清除即使包含了作业( i = 10 )。
答案 0 :(得分:5)
在您的代码中,通过说
strncpy(dest,imsi,5);
您正试图写入一个统一指针dest
。它可以(并且很可能会)指向某些无法从程序访问的内存(无效内存)。它调用undefined behavior。
对于具有UB的程序,没有什么可以保证的。它可以按预期工作(取决于您实际上期待的),或者它可能崩溃或打开您的银行帐户并转移所有钱都捐给了一些潜在的恐怖组织。
N.B - 我希望通过阅读最后一行你害怕,所以底线是
不要尝试写入任何未初始化的指针(内存区域)。周期。强>
答案 1 :(得分:1)
此代码的行为是不可预测的,因为指针dest在初始化之前使用。观察到的行为的差异仅与根本原因错误间接相关,根本原因是未初始化的变量。在C中,程序员有责任为strncpy()函数的输出分配存储空间,而你还没有这样做。
最简单的解决方法是定义一个输出缓冲区,如下所示: char dest [10];
答案 2 :(得分:0)
假设您将此C源代码编译为某种“常规”体系结构的机器代码,然后运行它,则未定义UB的可能影响基本上归结为寄存器或内存中浮动的值最终被使用。 / p>
如果编译器碰巧两次都使用相同的值,并且该值恰好指向可写的内存地址(并且未覆盖任何会破坏printf的内容),则肯定可以正常工作。 UB不会保证崩溃。它不保证任何内容。 UB的部分目的是让编译器做出假设并根据它们进行优化。
对周围代码的任何更改都会影响该函数的代码生成,因此会影响调用发生时相关寄存器中的内容,或dest
使用的堆栈插槽。从不同的堆栈地址读取将为dest
提供不同的值。
在主函数调用之前,对动态链接器函数的调用可能已经弄脏了一些内存,使一些指针漂浮在其中,甚至显然包括一些可写内存。
或者main的调用者可能有一个指向寄存器中某些可写存储器的指针,例如堆栈地址。
尽管可能性较小;如果编译器甚至在进行调用之前甚至不设置寄存器,那么strncpy
可能会获得main的第一个arg(整数argc),除非编译器首先将该寄存器用作临时寄存器。但是字符串字面量通常进入只读存储器,因此在这种情况下这是不太可能的解释。 (即使在像ARM这样的ISA /调用约定中,gcc临时的最喜欢的寄存器是R0,返回值寄存器也是也是第一个arg传递寄存器。如果禁用了优化,则语句将单独编译,大多数表达式将使用R0。)