【问题标题】:C variable confusionC变量混淆
【发布时间】:2016-01-14 14:05:01
【问题描述】:

在我的一项作业中,我看到使用了这条线:

int index = -1, k;

我不确定当有一个变量的条目时会发生什么。 当它有两个条目时,变量“索引”到底是什么?

【问题讨论】:

  • 作业?拿回你的钱。这是一种非常糟糕的编码风格,你的导师应该更清楚。
  • @Rhymoid 一些作业故意使用 bad style,这样你就可以接受训练,理解 C 语言中看起来怪异的结构。
  • 这不是模棱两可吗?编译器如何知道这里的逗号没有被用作逗号运算符。毕竟,index 被分配给表达式的值,并且表达式 -1,k 是有效的......除非可能没有定义 k。我想知道如果我这样做会发生什么:int k=3; int index=-1,k;。那么它应该将 3 分配给索引吗?
  • @mcleod_ideafix 定义不是赋值。试试你的例子,它只会作为重新声明而被拒绝。
  • 但是初始化是,并且初始化的右侧可以是任何有效的表达式,包括带有逗号运算符的表达式。当然我试过了,正如你所说,它不能编译,但如果我写:int k=3; int index=(-1,k); 它可以工作

标签: c variables integer


【解决方案1】:

这是 2 个变量的定义,它们都是同一类型的 intindexk。只有index-1 初始化,k 未初始化。

【讨论】:

  • “这是 2 个变量的定义”——不,不是。定义!=声明
  • @Mecki 那些定义,你分配存储。 extern int j; 是声明!参见例如stackoverflow.com/a/1410632/3093378 所以请不要投反对票,除非你 100% 确定。
  • 来源错误。 SO 不权威。 open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf ISO-C 表示变量不需要存储,除非您在声明语句之外使用它。例如。第 123 页说 int *pi; 是一个声明,即使它不是 external 并且指针需要一些空间(通常是 4/8 字节),但它只需要在被地址初始化、分配或引用时才需要空间。
  • ISO C 标准第 129 页:consider a declaration -- T D1 -- where T contains the declaration specifiers that specify a type T (such as int) and D1 is a declarator that contains an identifier ident.。第 137 页:typedef T type_ident; type_ident D; 两者都是上面一行的命名声明,适用于任何类型 T,如果 Tint 也是如此。
  • @Mecki Related question,所以也许我们可以弄清楚到底发生了什么。
【解决方案2】:

它只是定义了两个int类型的变量,其中一个(index)初始化为-1,另一个(k)未初始化。

这是一种糟糕的风格,因为它看起来真的很混乱。

【讨论】:

  • 没有风格的好坏之分,因为这些术语没有客观的定义,没有风格之神或风格法则。仅仅因为你认为它是糟糕的风格并不意味着它是糟糕的风格。您的个人品味/偏好就是您的想法,这是主观的。
  • 是的。在你的回答中,我明白了原因。
  • 而且您还根据 ISO C 标准误用了“定义”一词。你试图挑剔我的回答,然后你犯了这样的错误?您如何开始挑选自己的答案?
  • @Mecki 我不是在谈论显然具有不同语义的代码的“等效性”。停止你的废话。
  • 我从来没有说过代码在 C 标准方面是等价的,我说它只是等价的,意思是按照我写的方式编写,它会做完全一样的事情,不管 C 编译、平台、代码、系统或月相(这就是人们所说的等价,这个词的定义比计算机早了几个世纪)。
【解决方案3】:

正如其他几个人所说,这是一个两个变量的声明。它100%等同于

int index = -1;
int k;

现代 编码风格会鼓励你这样写。然而 - 那里有很多旧的 C,在 1980 年代和 1990 年代,分组变量声明是 首选 风格。 随机选择一个尘土飞扬的牌组,我向你保证你会看到类似的东西

register f, r, (*hstat)(), (*istat)(), (*qstat)();
int status;

或许

extern char level;
int newtry[31],newother[31],*r,*q,*p,n,sum,first;
int ii,lastwhite,lastred;

所以你需要理解它的含义。可悲的是,它们可能会变得非常混乱,例如

int const* a, b;

相当于

const int *a;
int b;

这就是为什么现代编码风格更喜欢每个声明一个变量的原因。

(为什么人们在过去更喜欢对声明进行分组?我不知道。就我个人而言,我猜它可以帮助您在 80x25 玻璃 tty 上同时查看更多代码,但我实际上从未有过经验,所以。)

【讨论】:

  • 好答案...只是一个猜测,也许回到这些“黑暗的日子”,它可能帮助编译器在更短的时间内完成任务:)
【解决方案4】:

在这段代码中,“index”和“k”都是整型变量,变量“index”由-1赋值(即index的值为-1)。这称为变量初始化。

【讨论】:

    【解决方案5】:

    在 C 中,逗号运算符 , 的优先级低于赋值运算符 =。因此,表达式

    int index = -1, k;
    

    被解析为

    //The parentheses are not legal in C, but it's what the parser does.
    int ((index = -1), k);
    

    您看,该行声明了int 类型的变量。第一个叫index,初始化为-1,第二个叫k,没有初始化。

    您可以在此处找到有关运算符优先级的详细概述:
    https://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B#Operator_precedence
    请注意,逗号运算符是该列表中的最后一个!


    同样,您可能会看到这样的 C 代码或类似代码:

    if(condition) foo += 7, doSomething();
    while(i += 2, i < 42) ...;
    

    这相当于

    if(condition) {
        foo += 7;
        doSomething();
    }
    
    i += 2;
    while(i < 42) {
        ...
        i += 2;
    }
    

    但更简洁(许多 C 程序员喜欢简洁!)。同样,在这两种情况下,逗号运算符都用于将两个内容融合到一个语句中,从而避免编写完整的块 {} 并防止重复增量 i += 2

    逗号运算符的这种用法是好是坏是品味和环境的问题。但是你可以肯定地在野外找到它的所有可能用途。

    【讨论】:

    • 对不起,那是错误的,在声明中,逗号是 not 运算符,而只是分隔声明符。关于喜欢简洁的 C 程序员?好吧,这是固执己见,没有程序员(值得他的薪水)喜欢令人困惑的构造。
    • @FelixPalmen 你说得对,我的表述不精确,因为代码中并非所有逗号实际上都是逗号运算符的实例。但是,这是一个有用的简化。无论在语法上如何称呼,逗号永远不会比任何其他运算符具有更高的优先级。当问题是如何解释 7 时,您是否将 (foo = 7, bar) 称为两个表达式的列表或两个用逗号分隔的表达式的列表是无关紧要的。是的,逗号在两种解释中的作用不同,但是解析的结构是一样的。
    【解决方案6】:

    假设这是函数范围内的代码:

    int index = -1, k;
    

    会做同样的事情

    int index = -1;
    int k;
    

    或相同

    int index, k;
    index = -1;
    

    即使代码不符合 C 标准,世界上没有任何已知的 C 编译器会对这三个代码块有任何不同的处理。

    在 C 语言中,您可以一次声明多个相同类型的变量 (int index, k;),或者定义一个变量(同时声明和初始化一个变量,int index = -1;),或者您可以同时执行这两项操作,声明多个并初始化它们或只是其中一个,如您的情况(int index = -1, k;)。

    【讨论】:

    • 您最后的声明是错误的。 int index = -1; 是一个初始化,而int index; index = -1; 只是一个赋值。
    • 初始化器与赋值不同。试试int a[3] = { 1,2,3};int a[3]; a = {1,2,3}
    • @Mecki 并不等同。尝试使用静态存储持续时间,即使在发出的可执行代码中也会看到差异(如果没有,请禁用优化)
    • @Mecki 并且编辑也无济于事......如果您对分配场景如此热衷,那么在典型的基于堆栈的 C 实现上编写它会导致相同的代码.. . 那是正确的。但不一样!
    • @Mecki 进行反证,阅读 C 标准。它对堆栈一无所知(只是一个提示)。
    猜你喜欢
    • 1970-01-01
    • 2014-06-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-02
    • 2011-04-30
    • 2017-11-03
    • 2013-11-30
    相关资源
    最近更新 更多