【问题标题】:a = &b vs *a = &b — pointer assignmenta = & b vs *a = & b — 指针赋值
【发布时间】:2017-05-16 09:25:36
【问题描述】:

我有一个指针和一个变量:

int *a;
int b;

作业之间有什么区别

a = &b;

*a = &b;

它们叫什么(比如指针声明之类的)?

【问题讨论】:

  • 也许你的意思是*a = b在最后一种情况下?
  • *a = &b; -- 你的编译器应该告诉你这是无效的。

标签: c pointers variable-assignment


【解决方案1】:

类型很重要。

  • 如果是a=&b,则分配有效。您将整数的地址(类型:int *)分配给另一个类型为int * 的变量,所以这是合法的。

  • *a=&b 的情况下,这是违反约束的(对于赋值运算符,请参阅第 §6.5.16.1/p1 章,约束,对于 Simple赋值),因此不是有效 C 语法,因此不需要由任何符合要求的编译器编译。为了使其成为有效的 C 语法,我们需要 enforce 一个 typecast,类似于

    *a= (int) &b;
    

    将使它成为满足所需约束的语法有效 C 语句。

    即使在那之后,结果也是由实现定义的。#note 在这里,您基本上是在尝试将整数的地址(类型:int *)分配给另一个类型的变量int*a 的类型为 int)。从指针到整数的转换是实现定义的行为。

    引用C11,第 §6.3.2.3 章,指针

    任何指针类型都可以转换为整数类型。除先前规定外, 结果是实现定义的。如果结果不能用整数类型表示, 行为未定义。 [....]

[....] 它们叫什么?

它们都是赋值语句。


注意:

考虑到a 已经指向一个有效的内存位置。否则,取消引用无效指针会自行调用 undefined behavior

【讨论】:

  • 那不也是UB吗?
  • @coderredoc - UB 与实现定义的结果不同。一种意味着你的处理器可能会爆炸,另一种意味着你会得到一些东西,但无法预测它是什么。
  • 我得到一个带有 Clang 的 compile-time error -- 你确定 int* 可以隐式转换为 int 吗?
  • @Quentin - 您作为错误标志的警告可能与此有关。正如所引用的,C 标准在这里不需要诊断。
  • @SunQingyao - 你错了。如果标准使用实现定义的结果定义了值更改,则它不会为实现提供执行除值更改之外的任何操作的余地。就像我说的,UB 在实现上没有那么严格。
【解决方案2】:

注意=左右的类型。

&bint *a 也是 int **aint


* 有不同的含义有点令人困惑:

int *a; — 这里的* 表示a 将是一个指针;

*a = ...; — 这里的* 表示我们更改的不是存储在a 中的地址,而是位于该地址的值。


所以a = &b的意思是“把b的地址写到a”,

*a = &b的意思是“将b的地址写入*a,即写入a中存储的地址”。


假设我们有这种情况:

   Address  Value
 a 0x0001   0x0004
 b 0x0002   70
   0x0003   80
   0x0004   90

目前a0x0004*a90

如果您选择a = &b,则a 将是0x0002*a 将是70

但是如果你做*a = &b,a不会改变,但是*a,即地址0x0004处的值,会变成0x0002

【讨论】:

    【解决方案3】:

    作业之间有什么区别

    a = &b;
    

    *a = &b;  
    

    是的。在第一种情况下,a&bb 的地址)都是 int * 类型。它们是可分配的。
    对于*a = &b*a 的类型为int,而&b 的类型为int *。两种类型不兼容,&b 的类型未显式转换为*a 的类型。这是违反约束的。话虽如此:int 类型不能保存指针对象。唯一能够保存指针对象的整数类型是intptr_tuintptr_t

    7.20.1.4 能够保存对象指针的整数类型

    1 以下类型指定了一个有符号整数类型,其属性是任何指向void的有效指针都可以转换为该类型,然后再转换回指向void的指针,结果将与原始指针进行比较:

    intptr_t  
    

    以下类型指定一个无符号整数类型,其属性是任何指向void的有效指针都可以转换为该类型,然后转换回指向void的指针,结果将与原始指针进行比较:

    uintptr_t
    

    这些类型是可选的。


    它们叫什么(比如指针声明什么的)?

    它们是赋值语句。

    【讨论】:

      【解决方案4】:

      一个显着的区别是第二个赋值是格式错误的 C(因为 违反约束):

      *a = &b;
      

      错误:赋值从没有强制转换的指针生成整数 [-Wint-转换]

      C11 §6.5.4/3,强制转换运算符:

      涉及指针的转换,除 6.5.16.1 的约束,应通过显式的方式指定 投射

      在 C89 中引入了显式转换的要求,以禁止在整数和指针类型之间进行隐式转换的不良做法。

      这个规则唯一的例外是你可以用0整数常量来赋值指针值,它代表空指针常量:

      a = 0; // more idiomatically: a = NULL;
      

      【讨论】:

        【解决方案5】:

        就像所有其他答案已经指出的那样,给定变量int *aint b

        • 赋值a = &b有效(并将b的地址赋值给指针a,这样*a就可以用来访问b),而
        • 分配*a = &b 是违反约束的,因为它试图将b 的地址分配给a 指向的整数,如果没有显式转换,这是不允许的。

        What might be confusing you,然而,是变量声明:

        int b;
        int *a = &b;
        

        有效的,并且与以下内容完全相同:

        int b;
        int *a;
        a = &b;    // not *a = &b!
        

        这是一个非常方便的简写,因为您几乎总是希望在声明变量后立即对其进行初始化(如果只是为了确保在初始化之前不会意外尝试使用它)。但是当您第一次遇到该语法时可能会感到困惑,因为它看起来就像您将&b 分配给*a,而实际上是a 本身正在使用该值进行初始化&b。这只是你必须学习的东西:变量初始化与普通赋值不同,尽管它看起来非常相似。

        【讨论】:

        • 这种潜在的混乱正是我更喜欢写int* a = &b; 以确保a 的类型为int* 并被分配b 的地址的原因。
        • @DavidZwicker:这是突出差异的一种方式,尽管它也有自己的缺陷:int* a, b not 声明了两个int* 类型的变量!此外,它不适用于更复杂的东西,比如指向数组或函数的指针(尽管你总是可以typedef 那些)。
        • 同意!我想最干净的解决方案是 typedef 指针,但在简单的情况下这可能是矫枉过正(实际上会损害可读性)。
        【解决方案6】:

        给定类型,以下分配将是有效的:

         a = &b; // int * = int *
        *a =  b; // int   = int
        

        在第二种情况下,a 必须指向有效的内存位置,否则行为未定义。

        *a = &b;  // int = int *
        

        是违反约束的,编译器会对你大喊大叫。

        【讨论】:

          【解决方案7】:

          第一个,int a = &b;将变量“b”的地址复制到 “一个”。

          第二个,int *a = &b;将变量“b”的地址复制到 位置“a”指向。

          【讨论】:

          • 对于第二行,您说“将变量“b”的地址复制到“a”指向的位置,但a 指向哪里? (这是我说你对第二行的解释不可能正确的方式,第二行的行为实际上是初始化a,所以它指向b;也就是说,之后你有a==&b .) 这是reference
          【解决方案8】:

          第一个没问题,但第二个调用 UB。 (除非a 指向一些有效的内存)

          【讨论】:

            【解决方案9】:

            肯定有区别
            &代表指针(从指针可以取值)
            *代表值
            a=&b(代表b的相等点)
            *a=&b(表示b的等分值)

            Helped Tutorial

            【讨论】:

            • C 没有引用。
            【解决方案10】:

            首先让我澄清一下整数变量和指针变量之间的区别:

            (1) 整数变量(例如:int b,在这种情况下)用于存储整数的值(长度为 4 字节)。 'b' 的值存储在某个内存位置(例如 0x00000001 )。

            (2) 指针变量(例如:int * a,在这种情况下)用于存储整数变量的内存位置。也就是说,在'a'中我们可以存储一个整数变量的地址。指针变量指向的值可以使用'*'操作符取消引用。因此,'a' 将具有地址,而 '*a' 将具有由 a 中包含的值(地址)指向的值。

            现在回答你的问题:

            假设 b = 4 并且 b ( &b ) 的地址是 0x00000001 (十六进制表示法)。

            在第一个类型赋值a = &b中,变量整数b的地址被存储在a中(因为a是一个指针变量)。现在“a”的值为 0x00000001,“*a”的值为 4。

            在第二种类型赋值*a = &b中,变量b的地址被存储在a指向的内存位置,即在0x00000001内存位置本身的值为0x00000001。现在“a”的值是 0x00000001,“*a”也将具有相同的值 0x00000001。

            【讨论】:

              【解决方案11】:
              int *a;
              int b;
              
              Is there any difference between assignments `a = &b` and `*a = &b`.
              

              T 类型的任何变量var 在内存中都有某个位置,其地址要么由编译器分配,要么由静态或动态链接器分配。一些变量的地址可以通过&var获得,类型为pointer to T。因此,当您应用 & 运算符时,您会将类型嵌套在另一个指针中。 a=&b 是正确的。

              另一方面,*a=&b 不正确。您尝试在变量 *a(类型为 int)中存储指向变量 b(类型为 pointer to int)的基地址的指针。在指针有 64 位而 int 有 32 位的体系结构中,这将导致失败。另一方面,在指针和 int 具有相同长度的体系结构上,如果插入强制转换,这是可能的。编译器不会自动插入从int*int 的强制转换。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2012-07-26
                • 1970-01-01
                • 2018-01-29
                • 2015-11-14
                • 1970-01-01
                • 2021-11-28
                • 1970-01-01
                • 2014-03-29
                相关资源
                最近更新 更多