8
回答
哈 ,喷下 static 我的个人观点
科大讯飞通用文字识别100000次/天免费使用。立即申请   

@乌龟壳 我专门喷个水帖,讨论下static吧。算个人片面观点,抛砖引玉,欢迎大家指正。

static ,基本的三个用法,针对数据(我的个人习惯用语,可等同为C语言教科书上的变量),有 函数内的,和函数外的。 另一个用法是针对函数本身的。

对于函数本身的,可以算作一种封装,

static void func(void){
    return ;
} 

先说最后这种。这里的主要作用就是封装,好处包括几个方面。

第一,函数名可重复,全局函数(默认无static 的),不能重名。 

第二,从模块化角度,内部封装的执行逻辑单元(就是函数吧),可以理解成接口内部确定无需与外部对接,此时这些函数的接口数据就不存在需要边界检测的问题。例如:

static signed char inc(signed char a){
    return a+1;
}

signed char g_inc(signed char a){
   if ((a+1) < a){
     return a;
   }else{
     return a+1;
   }
}



上述两个函数一个全局的,一个是局部的,因为局部的,只有本c文件(可看作一个模块)内部调用,所以被调用者是显式可见,或设计时可先定义的。所以没有必要进行边界检测。而下面全局的函数,由于会对外(部模块)开放,则需要进行边界检测,外部由于不确定模块内部处理逻辑,所以外部没有责任也很难直接完成边界检测。

这样static 的函数定义,除了重名这个形式上的好处外, 还能有效提高模块内部数据处理合理性的问题。通俗的讲, a -> b -> c ->d ,a如果做了边界检测,则依次被调用的b,c,d函数就不需要检测了。

回过头来,static 针对数据而言。 在函数内的,此时,含义应该理解成他是一个函数的组织。一个函数形象的比喻,是个水管子,来处理流动的水(被处理的数据),此时被处理的数据并不属于该函数,要么指针方式给如,要么参数方式传递进来。对于 函数内那些没有加 static的数据, 则表示与处理逻辑有关系,其关联仅在于单次处理逻辑中必须的临时存储空间(本身也确实存在堆栈或寄存器中)。

而函数内的static 则和前后处理的数据,有关联。单反有函数内static 的函数,你总能找到点迭代的算法在里面。哈。

函数外的static则是看作一种被封装的,具有常态存储的数据,其有自己固定的存储空间。其生命周期和函数无关。这个相对而言主要针对全局数据。此时更多从模块封装的角度来看。

哈,基本这么多。再说可能有复杂了。。 

如果说非要把c语言看成过程函数化的语言,我就没什么说道了。不过如果基于c文件,按照模块和封装的思想来设计,static确实有很大的价值。而且诠释的含义有所不同。 如果一个模块我们可以看作如一个汽车里的发动机,传动系统,或者刹车系统等等,作为一个系统的固有组成部分。那么,分离设计,控制好封装,确定好接口规范,则可有效提高开发效率和测试效率,也便于系统的后续调整改动。这个时候,合理使用static 就是有写说法的了。

<无标签>
举报
中山野鬼
发帖于1年前 8回/698阅
共有8个回帖 最后回答: 1年前
变量作用域值得说这么多吗?换句话说,一般人谁会没事都用全局名称而不用局部名称?变量作用域目的是让变量具有层次,方便命名。如果从语法角度,java比c高级多了,命名空间package比c的两层结构extern/static更灵活。c命名为什么总那么长?就是因为名字空间层次不够,只能在名字上加一堆前缀来方便划分。这无所谓对错,只是好奇你和宏哥盛赞这东西的赞点让我难以理解,不知道是不是有什么没考虑到的。现在看来不外乎就是一种比java低级的命名空间管理手段而已,见谅
面向对象称之为单例模式,函数式称之为闭包。但总体而言,闭包有利于追踪静态变量,而单例模式则把算法逻辑隐藏太深导致可读可维护奇差。所以,纯粹的面向对象是错误的。没有面向对象也是错误的。

引用来自“乌龟壳”的评论

变量作用域值得说这么多吗?换句话说,一般人谁会没事都用全局名称而不用局部名称?变量作用域目的是让变量具有层次,方便命名。如果从语法角度,java比c高级多了,命名空间package比c的两层结构extern/static更灵活。c命名为什么总那么长?就是因为名字空间层次不够,只能在名字上加一堆前缀来方便划分。这无所谓对错,只是好奇你和宏哥盛赞这东西的赞点让我难以理解,不知道是不是有什么没考虑到的。现在看来不外乎就是一种比java低级的命名空间管理手段而已,见谅

好吧, 我只能说,我没解释清楚,如果从语法角度,java比c高级多了,命名空间package比c的两层结构extern/static更灵活” 针对这句话,或许我们可以通过一个实例,以c和java分别表述一下,看看static的用法大家理解上的差异。哈。简单说,你用一个package的例子,并大体介绍一下,我看一下,从构造逻辑上,是否能用static来做个等同效果的设计。

当然语言嘛,是工具,干好自己的事情就可以。无非如果大家都有空,可以玩一玩,哈。补充了这句话是担心带坏这里的小孩子,为了形式化的设计而设计。

引用来自“AutoPlus”的评论

面向对象称之为单例模式,函数式称之为闭包。但总体而言,闭包有利于追踪静态变量,而单例模式则把算法逻辑隐藏太深导致可读可维护奇差。所以,纯粹的面向对象是错误的。没有面向对象也是错误的。
这点我认同。面向对象的分析方式,无处不再。包括从一群女人中区分出,哪个更应该下手。哈。对象化是人类思维的一个特点。
package org.wuguike.utils

class P {
    public int x;
    private int y;
    public static int z = 1;
}

package org.wuguike.helper

class P {
    public int x;
    private int y;
    public static int z = 2;
}

package org.wuguike.test

class P {
    public static void Main(){
        printf(org.wuguike.utils.P.z);
        printf(org.wuguike.helper.P.z);
    }
}



--- 共有 5 条评论 ---
乌龟壳回复 @中山野鬼 : 两个P是类,不是成员,问题关键是c的static好在哪里,我举的例子能证明java/c++这种namespace的设计,比c的extern/static的更灵活方便,感觉static只是一种很低程度的语法结构,到底好在哪里? 1年前 回复
中山野鬼回复 @乌龟壳 : 哈,还是有点对不上频道。这两个P是公开的,然后呢?之所以命名不冲突,我的理解,两个P作为两个不同类的成员而已。 1年前 回复
乌龟壳回复 @中山野鬼 : 两个P类都是公开的,因为有package,命名的时候没半点纠结的地方。c的extern变量处理起来就麻烦些。这很平常,没什么,主要是c的static不平常在哪里你没讲清楚我觉得 1年前 回复
中山野鬼回复 @乌龟壳 : 麻烦解释下特色。哈,不丢脸,java不熟,所以我想知道你上面代码具体想表达的含义。不是代码本身,而是语法用途方面。 1年前 回复
乌龟壳分别是三个文件,我写一起了而已,也不用管跑不跑得起来,反正意思到了。 1年前 回复

引用来自“乌龟壳”的评论

package org.wuguike.utils

class P {
    public int x;
    private int y;
    public static int z = 1;
}

package org.wuguike.helper

class P {
    public int x;
    private int y;
    public static int z = 2;
}

package org.wuguike.test

class P {
    public static void Main(){
        printf(org.wuguike.utils.P.z);
        printf(org.wuguike.helper.P.z);
    }
}



这个就属于理解错误。Java 的 static 和 C 的 static 在语义上完全是两码事。

C 的 static 目的是防止外部文件引用本文件,造成命名冲突;另外,就是提供一个共享实例,全进程/线程只有一个对象。最常用的就是静态变量:

static struct P *p = null;
struct P *getP() {
    if (p == null) p = malloc(...);
    return p;
}

Java 的 private public 才是相当于 C 的 static extern 目的。如果要制造 C 的 static 静态变量目的(C 并不关心 struct 的字段可不可以隐藏,C 的哲学是程序员应该具备关心成员的本分),应该相当于:

public class P {  
    private P() {}  
    private static P instance = null;  
    public static P getInstance() {  
        if (instance == null) {    
            instance = new P();  
        }    
        return instance;  
    }  
}  

{
    P p1 = P.getInstance();
    P p2 = P.getInstance();
}


--- 共有 6 条评论 ---
乌龟壳回复 @AutoPlus : 建议你把我和野鬼说的朗有感情地朗读十遍再回我,你都没看清我在说什么 1年前 回复
AutoPlus回复 @乌龟壳 : 命名空间和包和 static 有什么关系?这都能扯出理论更是奇怪了。import org.mongodb.path 和 include org/mongodb/path 有什么本质区别吗?语义这东西,还不是编译器作者想怎么解释就怎么解释? 1年前 回复
乌龟壳回复 @AutoPlus : 你一开始就说得有问题,我能不能分清static和我与野鬼的讨论内容没关系,你一直在说什么java的static和c的static,但我说的重点是package也就是c++的namespace。 1年前 回复
AutoPlus回复 @乌龟壳 : 另外,Java 最后要解释到 C 的层级,毕竟需要 C 的 OS API 和系统调用,Java 也必须兼容到 C 。C 出现在前,Java 后,Java 的 private public 也只是借鉴 C 的隐藏原理。 1年前 回复
AutoPlus回复 @乌龟壳 : 本质上是你对 C 和 Java 的语法语义都理解错误。两个不同语言的关键字,你非要用一个意思理解。static 和链接器没有本质上的关系,对于动态链接库,static 仍然提供变量隐藏的目的。Java 是通过 private public 提供隐藏的目的。这是两个语言的设计本质。 1年前 回复
顶部