我在哪里可以找到奇怪的,特定的C语法规则?

时间:2018-05-08 14:27:25

标签: c syntax

我将参加考试,我的老师会问一些奇怪的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;

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

3 个答案:

答案 0 :(得分:2)

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

d[i++][++i][++i]的行为未定义。巧妙地告诉你的老师。

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

,你的代码会更清楚
int a=012; // octal constant.

答案 1 :(得分:2)

对我而言,您的老师似乎在问问题是否存在未定义的行为。

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

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

  1. 在不同平台上编译代码
  2. 使用不同的编译器编译代码
  3. 使用相同编译器的不同版本编译代码
  4. 使用结果构建矩阵。您会发现它们不同
  5. 向老师展示结果并让他解释为什么会发生这种情况
  6. 这样你就不会说他错了,你只是在展示一些事实,而你却表明你愿意学习和工作。

    考试之前做了很长时间,以便教师可以调查并思考他的问题,以便他能及时更改考试。

      

    我找不到任何网站或书籍的规则。我在哪里可以找到?

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

答案 2 :(得分:1)

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将整数值格式化为八进制:1010 == 128

<小时/>

  1. 序列点是程序执行中的一个点,其中表达式已被完全评估并且已应用任何副作用。在评估了&&||?:运算符的左操作数之后,序列点出现在语句的末尾,函数参数的评估和函数调用之间,以及其他几个地方。完整清单见附件C.
  2. 或者甚至是同一版本的不同运行,虽然在实践中你不会看到值在运行之间发生变化,除非你做了一些非常隐蔽的事情。