搜索
查看: 2058|回复: 6
打印 上一主题 下一主题

谁说C语言很简单?

[复制链接]
跳转到指定楼层
楼主
发表于 2012-8-5 23:09:33 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 virfyf 于 2012-8-6 08:06 编辑

是的,C语言并不简单,让我们来看看下面这些示例:
(Ctrl+A看答案)

为什么下面的代码会返回0?(这题应该很简单吧)
[mw_shl_code=c,true]int x;
return x == (1 && x);[/mw_shl_code]
本题主要是关于C/C++中变量初始化的问题。


为什么下面的代码会返回0而不是-1?
[mw_shl_code=c,true]return ((1 - sizeof(int)) >> 32);[/mw_shl_code]
答案:sizeof 是一个unsigned的类型,所以……

代码作用域是一件很诡异的事,下面这个函数返回值是什么?
[mw_shl_code=c,true]int x = 5;
int f() {
  int x = 3;
  {
    extern int x;
    return x;
  }
}[/mw_shl_code]
答案:5
函数和函数指针可以相互转换。下面的语句哪些是合法的?
[mw_shl_code=c,true]int (*pf)(void);
int f(void)
{

   pf = &f; // 没问题
   pf = ***f; // 取址?
   pf(); // 函数指针可以调用?
   (****pf)();  // 这又是什么?
   (***************f)(); // 这个够变态了吧?
}[/mw_shl_code]
答案:全部合法。            

初始化可能是ISO C中最难的部分了。无论是MSVC 还是GCC 都没有完全实现。GCC 可能更接近标准。在下面的代码中,i.nested.y 和i.nested.z的最终值是什么?
[mw_shl_code=c,true]struct {
   int x;
   struct {
       int y, z;
   } nested;
} i = { .nested.y = 5, 6, .x = 1, 2 };[/mw_shl_code]
答案:2和6

下面这个示例是C语言的痛,main函数返回值是什么?
[mw_shl_code=c,true]typedef struct
{
  char *key;
  char *value;
} T1;

typedef struct
{
  long type;
  char *value;
} T3;

T1 a[] =
{
  {
    "",
    ((char *)&((T3) {1, (char *) 1}))
  }
};
int main() {
   T3 *pt3 = (T3*)a[0].value;
   return pt3->value;
}[/mw_shl_code]
答案:1(你知道为什么吗?)

下面这个例就更变态了。在GCC的文档中,这个语法是合法的,但是不知道为什么GCC并没有实现。下面的代码返回 2.
[mw_shl_code=c,true]return ((int []){1,2,3,4})[1];[/mw_shl_code]

在下面的这个示例中,有一个“bar” 函数及其函数指针 “pbar” 的两个拷贝(static 类型一般作用于语句块或文件域)
[mw_shl_code=c,true]  int foo() {
     static bar();
     static (*pbar)() = bar;

  }

  static bar() {
    return 1;
  }

  static (*pbar)() = 0;[/mw_shl_code]

下面的这个函数返回值是什么?取决于编译器是先处理unsigned long转型,还是负号。
[mw_shl_code=c,true]unsigned long foo() {
    return (unsigned long) - 1 / 8;
  }[/mw_shl_code]
如果是: ((unsigned long) - 1) / 8,那将是一个很大的数
如果是: (unsigned long) (- 1 / 8 ), 那将是 0
是的,这样使用C语言可能很奇怪,不过我们可以从另一方面了解C语言的很多我们不常注意的特性。C语言其实并不容易。(From CoolShell.cn)
沙发
发表于 2012-8-5 23:32:53 | 只看该作者
新手飘过
板凳
发表于 2012-8-5 23:50:08 | 只看该作者
{:soso__2252603165368053288_4:}我听一个老鸟说:学C语言十年才算入门....噢..
地板
发表于 2012-8-9 13:07:33 | 只看该作者
{:soso__11824716995429377336_2:}  C这东西 你想要它难就难你想让他易就易 .....  
5#
发表于 2012-8-9 21:35:05 来自手机 | 只看该作者
同意板凳和地板的看法
6#
发表于 2013-5-5 04:56:55 | 只看该作者
酷壳上面的老文章了,问题好多
第一个
  1. int x;
  2. return x == (1 && x);
复制代码
既然可以return,那么一定在一个函数里面,所以x必然是局部变量
int型局部变量不显示初始化时,它的值不确定

所以,如果 x==1
那么 (1 && x) == (1 && 1) = 1
1==1
返回值是1
此外,如果x==0,返回值也是1

第二个
  1. return ((1 - sizeof(int)) >> 32);
复制代码
sizeof(int) 得到size_t类型,然后计算1-sizeof(int),得到一个size_t类型
size_t是一个unsigned intergal type
unsigned intergal type和signed intergal type的存储空间相同
对于微软的编译器实现,32位机器上size_t是32位
然后计算>>32,位移长度和存储长度相等,行为未定义…

第三个
  1. int x = 5;
  2. int f() {
  3.   int x = 3;
  4.   {
  5.     extern int x;
  6.     return x;
  7.   }
  8. }
复制代码
extern int x;表示x已经定义在其它地方,要求链接器查找这个x然后将值进行替换
因为上一层的x=3;是局部变量默认的存储属性,链接器是看不见它的
所以会把外层的一个x=5解析到这里来
但是这个例子不好…因为extern不这么用,至少我没见过用extern解析到同一个文件file scope的变量上去的…

7#
发表于 2013-5-5 12:06:34 | 只看该作者
第八个
  1. int foo() {
  2.      static bar();
  3.      static (*pbar)() = bar;

  4.   }

  5.   static bar() {
  6.     return 1;
  7.   }

  8.   static (*pbar)() = 0;
复制代码
在C89中,函数返回类型是可省略的,static bar(){ return 1;} 还算可以理解
但是 static (*pbar)()=0该如何做词法分析?(*pbar)()是一个函数指针,返回类型默认为int,然后加上static修饰,让文件外部不可见。但是=0又是什么?能想出来的类似物只有virture func() = 0表示一个纯虚函数,但那已经是C++的语法了
编译器认为*pbar重定义,有语法错误

第九个
  1. unsigned long foo() {
  2.     return (unsigned long) - 1 / 8;
  3. }
复制代码
(type)和-是单目运算符,优先度高于/这个双目运算符
所以是 ((unsigned long)(-1)) / 8
在我的64位机器上,输出是2305843009213693951
这个表达式的运算顺序是一定的,第二种说法不正确
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

广播台
特别关注
快速回复 返回顶部 返回列表