【问题标题】:Using memset with uninitialized variables将 memset 与未初始化的变量一起使用
【发布时间】:2021-05-10 19:47:12
【问题描述】:

这是没有未定义行为的有效 C 代码吗?

int main(){
 int a;
 memset(&a, 5, sizeof(int));

 return a;
}

我假设这等于只是做int a = 5

我试图了解在上面的示例中仅声明一个变量(不定义它)是否足以将其放入堆栈。

【问题讨论】:

  • C 没有堆栈的概念。只有变量,堆栈是实现细节。
  • 这不是声明。这是一个定义。只是它的初始值是不确定的。
  • 定义在做int a = 5
  • @EugeneSh.:C 中的每个定义都是一个声明。没有什么可以是定义,也不能是声明。
  • @AdrianMole:它在 C 2018 6.7 中。首先,它是一个声明说明符列表,后跟一个带有可选初始化的声明符列表,然后是一个分号。

标签: c integer memory-address memset


【解决方案1】:

这是没有未定义行为的有效 C 代码吗?

是的——一旦a变量在给定范围内声明(如函数或其他{ ... }分隔块),获取其地址并使用该地址访问变量是有效的在该范围内范围(就像您的memset 电话一样)。 当该范围结束时(即不再是“活动”)尝试使用该地址将导致未定义的行为;比如下面是UB:

int main()
{
    int* p;
    { // New scope ...
        int a;
        p = &a; // Pointer to "a" is valid HERE
    } // The scope of "a" (and its 'lifetime') ends here
    memset(p, 5, sizeof(int)); // INVALID: "p" now points to a dead (invalid) variable
}

但是,您的代码示例中有一个主要警告……

我假设这等于只执行 int a = 5。

问题是:它将5 分配给a 变量的每个组件字节,所以它这样做(假设是4 字节int):

int a = 0x05050505;

等同于:

int a = 84215045;

【讨论】:

  • 抱歉改成char
  • @Dan 不要改变你的问题。它使已经提供的答案无效。
  • 所以可以肯定地说,只在这里声明一个变量把它放在堆栈上,因此得到它的地址是有效的?
  • @Dan 是:一旦在给定范围(函数或其他 { ...} 分隔块)中声明了变量,获取其地址(并主要使用它)是有效的。
  • @AdrianMole 谢谢,你能对此发表答案吗?我会接受的,其他所有答案都集中在我遇到的数据类型错误上。
【解决方案2】:

来自 C 标准(7.23.6.1 的 memset 函数)

2 memset 函数复制 c 的值(转换为无符号 char) 到指向的对象的前 n 个字符中的每一个 秒。

所以这个电话

memset(&a, 5, sizeof(int));

不将变量a 设置为等于5。在内部,变量看起来像

0x05050505

这是一个演示程序

#include <stdio.h>
#include <string.h>

int main(void) 
{
    int a;
    
    memset( &a, 5, sizeof( int ) );
    
    printf( "%#x\n", ( unsigned )a );
    
    return 0;
}

它的输出是

0x5050505

您应该谨慎使用带有整数的函数memset,因为通常它会产生一个陷阱值。此外,结果取决于内部整数如何从 MSB 或 LSB 开始存储。

附:您在没有链接的块范围内声明了一个变量。它也是一个具有自动存储持续时间的变量定义。由于变量未显式初始化,因此它具有不确定的值。您可以应用运算符&amp; 的地址来获取定义变量的内存范围的地址。

【讨论】:

  • 抱歉改成char
  • 好的,可以这么说吗,只在这里声明一个变量把它放在堆栈上,因此获取它的地址是有效的?
  • @Barmar 这是一个错字。:)
  • @Dan 为什么获取地址无效?您声明(并定义)了一个对象。
  • 我不知道,我以为只声明它可能会将其地址传递给 memset UB,C 很奇怪。
【解决方案3】:

这不是未定义的行为。问题是它不是你所期望的。

结果

memset(&a, 5, sizeof(int));

包括将整数a 的四个字节中的每一个设置为5

【讨论】:

    猜你喜欢
    • 2014-07-07
    • 2011-03-03
    • 1970-01-01
    • 1970-01-01
    • 2016-07-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-24
    相关资源
    最近更新 更多