【问题标题】:Where can I find weird, specific C syntax rules?我在哪里可以找到奇怪的、特定的 C 语法规则?
【发布时间】:2018-05-08 14:27:24
【问题描述】:

我要参加考试,我的老师会问奇怪的 C 语法规则。喜欢:

int q=5;  
for(q=-2;q=-5;q+=3) { //assignment in condition part??     
    printf("%d",q);      //prints -5  
    break;     
} 

或者

int d[][3][2]={4,5,6,7,8,9,10,11,12,13,14,15,16};     
int i=-1;     
int j;     
j=d[i++][++i][++i];   
printf("%d",j); //prints 4?? why j=d[0][0][0] ?

或者

extern int a; 
int main() {     
    do {         
        do {              
            printf("%o",a); //prints 12         
        } while(!1);     
    } while(0);  
    return 0; 
} 
int a=10;

我找不到它统治任何网站或书籍。真是荒谬和不寻常。我在哪里可以找到?

【问题讨论】:

  • 嗯,很多老师确实会问一些愚蠢的东西,而且格式更差,让你感到困惑。
  • @Badiparmagi 因为学生应该思考他们所学的内容并相应地应用规则。它不必有任何意义或有用。
  • 有点吹毛求疵,你的问题更多地与语义有关,而不是 C 的语法。
  • 离题:它是关于我们要求推荐一个场外资源(书籍、外部网站、老师的评论)。它往往会吸引基于意见的答案。

标签: c syntax


【解决方案1】:

在我看来,您的老师似乎在问一些涉及未定义行为的问题。

如果你告诉他这是不正确的,你就是直接面对他。

但是,您可以执行以下操作:

  1. 在不同平台编译代码
  2. 用不同的编译器编译代码
  3. 用同一编译器的不同版本编译代码
  4. 用结果构建一个矩阵。你会发现它们不同
  5. 向您的老师展示结果并请他解释为什么会发生这种情况

这样你就不会说他错了,你只是在展示一些事实,并且表明你愿意学习和工作。

在考试前 做这件事,这样老师就可以调查并思考他的问题,以便及时更改考试。

我找不到它统治任何网站或书籍。我在哪里可以找到?

Where do I find the current C or C++ standard documents?。如果你在大学里有一个好的图书馆,他们应该拥有一本。

【讨论】:

  • 在不同的平台上,注意MSVC会在语句末尾递增i,而gcc在赋值之前递增i;我认为 ;-) 不错的答案,提高了。
【解决方案2】:

关于for(q=-2;q=-5;q+=3) {,您需要做的就是将其分解为其组件。先运行q=-2,然后测试q=-5,如果不是0(不是,因为它是一个值为-5的表达式),那么循环体运行一次。然后break 强制提前退出一个无限循环。表达式 then q+=3 永远不会到达。

d[i++][++i][++i] 的行为是未定义。委婉地告诉你的老师。

"%o" 格式表示 八进制 输出。 a 设置为十进制的 10,即八进制的 12。如果你写了,你的代码会更清晰:

int a=012; // octal constant.

【讨论】:

    【解决方案3】:

    C 语言标准的online version 有你需要的东西(我将在这个答案中提到);请记住,这是一个语言定义,而不是一个教程,因此对于还没有很多经验的人来说可能不容易阅读。

    话虽如此,您的老师正在向您扔一些犯规球。例如:

    j=d[i++][++i][++i];   
    

    由于多种原因,该语句导致未定义的行为。上面链接的文档第 6.5 节的前几段解释了这个问题,但简而言之:

    • 除少数情况外,C 不保证表达式的从左到右求值;它也不保证在评估后立即应用副作用;

    • 尝试在序列点之间多次修改对象的值1,或修改然后尝试使用对象的值而没有中间序列点,会导致未定义行为。

    基本上,不要写任何形式的东西:

    x = x++;
    x++ * x++;
    a[i] = i++;
    a[i++] = i;
    

    C 不保证每个++ii++ 都是从左到右进行评估的,也不保证每个评估的副作用都会立即应用。所以j[i++][++i][++i] 的结果不是很好定义的,不同的程序,甚至是同一个程序的不同版本,结果会不一致2

    AND,除此之外,i++ 的计算结果为 i当前 值;很明显,您老师的意图是让j[i++][++i][++i] 评估为j[-1][1][2],这会导致未定义的行为,因为您尝试在数组边界之外进行索引。

    这就是为什么我讨厌,讨厌,讨厌当老师向他们的学生扔这种代码时 - 它不仅不必要地令人困惑,不仅鼓励不良做法,而且更常见的是不只是简单的错误

    至于其他问题:

    for(q=-2;q=-5;q+=3) { //assignment in condition part?? 
    

    请参阅第 6.5.16 和 6.8.5.3 节。简而言之,赋值表达式有一个值(任何类型转换后的左操作数的值),它可以作为for 循环中控制表达式的一部分出现。只要赋值的结果非零(如上例),循环就会执行。

    printf("%o",a); //prints 12         
    

    请参阅第 7.21.6.1 节。 o 转换说明符告诉 printf 将整数值格式化为八进制:10<sub>10</sub> == 12<sub>8</sub>


    1. 序列点是程序执行中的一个点,其中表达式已被完全评估并且任何副作用都已应用。序列点出现在语句的末尾,在函数参数的计算和函数调用之间,在计算&amp;&amp;||?: 运算符的左操作数之后,以及其他一些地方。完整列表见附件 C。
    2. 甚至是同一构建的不同运行,尽管在实践中您不会看到值在运行之间发生变化,除非您正在做一些非常奇怪的事情。

    【讨论】:

      猜你喜欢
      • 2022-09-27
      • 2016-01-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-06
      • 2023-04-10
      • 2020-09-12
      • 2015-10-15
      相关资源
      最近更新 更多