TypeCodes

小心visual studio的“BUG”:变量的声明和使用

昨天一Q友找我帮忙写个C程序:其中函数fun要实现:求出2000到2500之内能被7或者17或者27整除,但是不能同时被7和17整除,也不能同时被17和27整除的整数。题目倒是不难,遂打开visual studio,默默地写出下面的程序。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <stdio.h>
void fun(int *a, int *n)
{
   int i = 2000, sum = 0;
   for(;i<2501;i++)
   {
      if( (i%7==0 || i%17==0 || i%27==0) && (!(i%7==0  && i%17==0)) && (!(i%17==0 && i%27==0)) )
      {
           *a++ = i;
           sum++;
      }
   }
   /* 返回符合要求元素的个数 */
   *n = sum;
}

int main()
{
   int a[120];
   int k;
   fun(a,&k);
   /* 使指针pt指向数组a的起始地址 */
   int *pt = a;
   for(;pt<a+120;pt++)
   {
         printf("%d\n",*pt);
   }
   printf("%d\n",k);
   return 0;
}

然后ctrl+F5执行,结果很意外的报错了:

1>------ 已启动生成: 项目: test, 配置: Debug Win32 ------
1>生成启动时间为 2014/3/18 16:30:15
1>InitializeBuildStatus:
1>  正在创建“Debug\test.unsuccessfulbuild”,因为已指定“AlwaysCreate”。
1>ClCompile:
1>  1.c
1>g:\vsprj\test\test\1.c(23): error C2143: 语法错误 : 缺少“;(在“类型”的前面)
1>g:\vsprj\test\test\1.c(24): error C2065: pt: 未声明的标识符
1>g:\vsprj\test\test\1.c(24): warning C4047: <:int”与“int *”的间接级别不同
1>g:\vsprj\test\test\1.c(24): error C2065: pt: 未声明的标识符
1>g:\vsprj\test\test\1.c(26): error C2065: pt: 未声明的标识符
1>g:\vsprj\test\test\1.c(26): error C2100: 非法的间接寻址
1>
1>生成失败。
1>
1>已用时间 00:00:00.65
========== 生成: 成功 0 个,失败 1 个,最新 0 个,跳过 0  ==========

无奈,只能根据上面的错误信息一个一个排查了。但很显然,第23行的int *pt = a;前面不缺分号,另外pt也声明为指针了,所以整个程序应该是没错的。检查了好几遍还是没看出问题,估计是vs编译出错了,于是决定用cygwin编译器重新编译一下。win+r打开cmd命令窗口,输入编译命令gcc G:\VSprj\test\test\1.c -o 1,然后直接执行1.exe。见证奇迹的时刻,竟然输出了数据。

cmd命令窗口gcc编译

回头想想,记得以前网上看过一个帖子,说是visual c++和visual studio对变量的声明要求特别严格,局部/全局变量一定要先声明在函数的最前面。于是把main函数中的指针pt声明调整到在fun函数的前面,再编译就没报错了。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
/**
 * 使用指针和数组求2000到2500之内能被7或者17或者27整除,但是不能同时被7和17整除也不能同时被17和27整除的整数
 * @author: vfhky 20140318 16:52
 */
#include <stdio.h>
void fun(int *a, int *n)
{
   int i = 2000, sum = 0;
   for(;i<2501;i++)
   {
      if( (i%7==0 || i%17==0 || i%27==0) && (!(i%7==0  && i%17==0)) && (!(i%17==0 && i%27==0)) )
      {
            *a++ = i;
            sum++;
      }
   }
   /* 返回符合要求元素的个数 */
   *n = sum;
}

int main()
{
   /* 用于保存符合要求的元素 */
   int a[120];
   int k;
   /* 先声明指针变量pt */
   int *pt;
   fun(a,&k);
   /* 再使指针pt指向数组a的起始地址 */
   pt = a;
   for(;pt<a+120;pt++)
   {
         /* 循环输出符合要求的元素 */
         printf("%d\n",*pt);
   }
   /* 输出总共符合要求的元素的个数 */
   printf("%d\n",k);
   return 0;
}

虽然说vs对变量的使用比较“苛刻”,造成类似上面的“bug”,提供的错误信息“误导”了开发人员。但是细想之下,又觉得vs这种做法很“规范”:任何变量在使用之前必须先声明!而为了增强程序的可读性,也应该把声明语句尽量放在最前面!

打赏支持

Comments »