歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

語言的歧義

語言是人與人相互溝通的途徑,而計算機語言則是人和計算機溝通的途徑。就算是任何再完美的自然語言都會有歧義,但是又是什麼讓人和計算計算機間產生了歧義呢?

下面這篇文章來自Gowri Kumar的Puzzle C一文。我做了一些整理,挑選了其中的一些問題,並在之後配上相應的答案(這些答案是我加的,如果需要原版的答案可以直接和本文作者Gowri Kumar聯系,作者的聯系方式可以從這裡得到)。

puzzle 1

此段程序的作者希望輸出數組中的所有元素,但是他卻沒有得到他想要的結果,是什麼讓程序員和計算機產生歧義?

#include <stdio.h>
#define TOTAL_ELEMENTS (sizeof(array) / sizeof(array[0]))
int array[] = {23,34,12,17,204,99,16};
int main()
{
    int d;

    for(d=-1;d <= (TOTAL_ELEMENTS-2);d++)
        printf("%d\n",array[d+1]);

    return 0;
}

 

解答:
運行上面的程序,結果是什麼都沒有輸出,導致這個結果的原因是sizeof的返回值是一個unsinged int,為此在比較int d 和TOTAL_ELEMENTS兩個值都被轉換成了unsigned int來進行比較,這樣就導致-1被轉換成一個非常大的值,以至於for循環不滿足條件。因此,如果程序員不能理解sizeof操作符返回的是一個unsigned int的話,就會產生類似如上的人機歧義。

puzzle 2

看上去非常完美的程序,是什麼導致了編程程序不通過?

#include <stdio.h>

void OS_Solaris_print()
{
    printf("Solaris - Sun Microsystems\n");
}

void OS_Windows_print()
{
    printf("Windows - Microsoft\n");
}

void OS_HP-UX_print()
{
    printf("HP-UX - Hewlett Packard\n");
}

int main()
{
    int num;
    printf("Enter the number (1-3):\n");
    scanf("%d",&num);

    switch(num)
    {
        case 1:
            OS_Solaris_print();
            break;
        case 2:
            OS_Windows_print();
            break;
        case 3:
            OS_HP-UX_print();
            break;
        default:
            printf("Hmm! only 1-3 :-)\n");
        break;
    }
    return 0;
}

解答:
程序員要以計算機的語言進行思考,不上上面那段程序導致的結果不止是歧義這麼簡單,而直接的結果是,導致計算機”聽不懂”你在說什麼。導致計算機聽不懂的原因是HP-UX中的’-'是減號?還是其他什麼?

puzzle 3

下面這段程序會輸出什麼,為什麼?

enum {false,true};

int main()
{
    int i=1;
    do
    {
        printf("%d\n",i);
        i++;

        if(i < 15)
            continue;
    }while(false);

    return 0;
}

解答:
1到14?不對,結果是1,因為continue的含義是不執行循環體之後語義,而直接到循環點。明顯while(false)不屬於循環體。導致這段程序的歧義就是:程序員沒有完全理解計算機語言中continue的含義。

puzzle 4

下面這段程序的輸出結果是:

#include <stdio.h>
#define f(a,b) a##b
#define g(a)   #a
#define h(a) g(a)

int main()
{
        printf("%s\n", h(f(1,2)));
        printf("%s\n", g(f(1,2)));
        return 0;
}

當然,你首先要了解##和#的用法,如果不懂的話,本題你可以直接跳過。
解答:
看到這段程序你可能會認為,這兩個printf輸出的同一個結果,可是答案卻非如此,本題的輸出是12和f(1,2),為什麼會這樣呢?因為這是宏,宏的解開不象函數執行,由裡帶外。

puzzle 5

下面這段程序的輸出是什麼

#include <stdio.h>
int main()
{
int a=10;
switch(a)
{
case ’1′:
printf(“ONE\n”);
break;
case ’2′:
printf(“TWO\n”);
break;
defau1t:
printf(“NONE\n”);

return 0;
}

解答:
本題我故意將語法敏感插件去掉,為了就是能得到更好的效果,這道題又是什麼讓歧義再次發生,如果不仔細你可能永遠都找不到答案,如果真到的到了那個時候,你是否會因為對default語義的懷疑,而不敢再使用default?本題的歧義點就是default,看好了是defau1t而不是default,不是關鍵字!為什麼計算能”聽懂”這樣的defau1t,算然它聽懂了,但它的理解卻是標號”defau1t”

puzzle 6

下面這段程序的輸出什麼?

#include <stdio.h>

int main()
{
    float f=0.0f;
    int i;

    for(i=0;i<10;i++)
        f = f + 0.1f;

    if(f == 1.0f)
        printf("f is 1.0 \n");
    else
        printf("f is NOT 1.0 \n");

    return 0;
}

解答:
你是否似曾相識?不錯這個問題在酷殼之前的博文《你能做對下面這些JavaScript的題嗎?》中曾今提到過,不要讓兩個浮點數相比較。所以本題的答案是”f is NOT 1.0″,如果你真想比較兩個浮點數時,你應該按一定精度來比較,比如你一定要在本題中做比較那麼你應該這麼做if( (f – 1.0f)<0.1 )

puzzle 7

下面兩個函數是否具有相同的原型?

int foobar(void);
int foobar();

下面這兩段程序將會幫你找到上題的答案
程序1

#include <stdio.h>
void foobar1(void)
{
    printf("In foobar1\n");
}

void foobar2()
{
    printf("In foobar2\n");
}

int main()
{
    char ch = 'a';

    foobar1();
    foobar2(33, ch);

     return 0;
}

程序2

#include "stdio.h"
void foobar1(void)
{
    printf("In foobar1\n");
}

void foobar2()
{
    printf("In foobar2\n");
}

int main()
{
    char ch = 'a';

    foobar1(33,ch);
    foobar2();

    return 0;
}

解答
程序片段一,沒有問題,程序片段二編譯報錯,這兩個程序告訴我們,foobar1(void)和foobar2()是有不同原型的的。我們可以在《ISO/IEC 9899》的C語言規范找到下面兩段關於函數聲明的描述

10.The special case of an unnamed parameter of type void as the only item in the list specifies that the function has no parameters

14.An identifier list declares only the identifiers of the parameters of the function. An empty list in a function declarator that is part of a definition of that function specifies that the function has no parameters. The empty list in a function declarator that is not part of a definition of that function specifies that no information about the number or types of the parameters is supplied.124)

上面兩段話的意思就是:foobar1(void)是沒有參數,而foobar1()等於forbar1(…)等於參數類型未知。

總結
看到這些C語言的題目,不禁讓我想起了巴別塔,計算機語言作為如此嚴謹的語言都有可能帶來如此多的歧義,更何況自然語言,更何況相互不通的自然語言。要杜絕歧義,我們就必須清晰的了解計算機語言每一個指令的語義。就如同人類,人類要和平就要相互了解各自的文化。願世界上人們清晰了解別人的語言的語義,願世界不再因為文化的不同而戰爭,原世界和平。

Copyright © Linux教程網 All Rights Reserved