通过静态局部变量看C,C++,C#,Java,PHP的特点
0 问题由来
对这个问题的思考来自于面向对象设计中的单例设计模式的实现。
C++中单例模式实现标准代码为:
#include <stdio.h>int init(){ printf("init()\n"); return 22;}int GetTheOnly(){ static int x = init(); return x;}int main(){ int only = GetTheOnly(); return 0;}</stdio.h>
在获取实例函数GetTheOnly()中, 静态局部变量用户存储唯一实例,并且初始化时直接使用init()函数动态初始化。
看起来如此简单,但同样的代码作为C来编译却不能通过,编译器在编译 static int x = init()这一行时报错:
错误:初始值设定元素不是常量
可见,C语言中的静态局部变量初始化时必须以常量赋值,也就是说这个初值必须在编译器就能确定。
细想一下,以调用函数来初始化静态变量,C++必须保证init();只运行一次。为达此目的,C++编译器必须增加额外代码,我能想到的C++编译器对于static int x = init(); 可能增加的伪代码如下:
static int x; static char flag = 0; if(flag == 0){ x = init();
flag = 1; } return x;
进而想看看其他几门语言对这个问题的处理,随后使用C#,Java,PHP进行了类似的试验,得出了小小的结论。
1 C#,Java根本就不支持静态局部变量两者只支持静态成员变量,不支持函数内的静态局部变量。想想也对,静态局部变量几乎总是可以使用静态成员变量来代替。
C#测试代码:
using System;namespace ConsoleApplication2{ class Program { static int x = 0; static int init() { Console.WriteLine("init()"); return 22; } static int GetTheOnly() { // static int x = 0; static local variable is NOT supported by C#. if(x == 0) { x = init(); } return x; } static void Main(string[] args) { GetTheOnly(); GetTheOnly(); } }}
Java测试代码:
public class t{ public static int init(){ System.out.println("init()\n"); return 22; } private static int x = 0; public static int getTheOnly(){ //static int x = 0; This line cannot be compiled, static local variable is NOT supported by Java if(x==0){ x = init(); } return x; } public static void main(String[] args) { getTheOnly(); getTheOnly(); }}
2 PHP对待静态局部变量与C相同,只支持以常量初始化
PHP测试代码:
<?phpfunction init(){ echo "init()\n"; return 22;}function getTheOnly(){ // static $x = init(); PHP only supports initializing static local vairalbel with constant. static $x = 0; if($x==0){ $x = init(); } return $x;}getTheOnly();getTheOnly();
3 一点思考
通过静态局部变量这一非常小的语言细节,可以发现这几门语言的特点。
C++ 编译器是勤劳全面的全才,尽量为用户提供更多的语言功能,而做到这些必须偷偷为用户生成代码,从而导致C++语言的复杂性和“冰山效应”。(想想C++的多重继承,栈上对象,复制构造。。。)
Java和C#则注重易用性,避免二义性,对于同样功能,只给用户一个正确的选择。(想想单继承、对象只能建立在堆上,垃圾回收)
C则始终保持其简洁高效透明,编译器老实巴交,看到了代码也基本上就能预测到生成的汇编。
PHP的结构化部分模仿C的语法,所以很多特性与之类似,然其毕竟是解释性语言,特别是变量名,类名等本身就可以作为变量的解释性语言特性,让其变得异常灵活。面向对象部分则模仿Java的语法,同时又充分体现了解释语言的特点。

Outils d'IA chauds

Undresser.AI Undress
Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover
Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool
Images de déshabillage gratuites

Clothoff.io
Dissolvant de vêtements AI

AI Hentai Generator
Générez AI Hentai gratuitement.

Article chaud

Outils chauds

Bloc-notes++7.3.1
Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise
Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1
Puissant environnement de développement intégré PHP

Dreamweaver CS6
Outils de développement Web visuel

SublimeText3 version Mac
Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Sujets chauds

Guide d'Active Directory avec C#. Nous discutons ici de l'introduction et du fonctionnement d'Active Directory en C# ainsi que de la syntaxe et de l'exemple.

Guide du générateur de nombres aléatoires en C#. Nous discutons ici du fonctionnement du générateur de nombres aléatoires, du concept de nombres pseudo-aléatoires et sécurisés.

Guide de la vue Grille de données C#. Nous discutons ici des exemples de la façon dont une vue de grille de données peut être chargée et exportée à partir de la base de données SQL ou d'un fichier Excel.

Guide des modèles en C#. Nous discutons ici de l'introduction et des 3 principaux types de modèles en C# ainsi que de ses exemples et de l'implémentation du code.

Java 8 présente l'API Stream, fournissant un moyen puissant et expressif de traiter les collections de données. Cependant, une question courante lors de l'utilisation du flux est: comment se casser ou revenir d'une opération FOREAK? Les boucles traditionnelles permettent une interruption ou un retour précoce, mais la méthode Foreach de Stream ne prend pas directement en charge cette méthode. Cet article expliquera les raisons et explorera des méthodes alternatives pour la mise en œuvre de terminaison prématurée dans les systèmes de traitement de flux. Lire plus approfondie: Améliorations de l'API Java Stream Comprendre le flux Forach La méthode foreach est une opération terminale qui effectue une opération sur chaque élément du flux. Son intention de conception est

Guide des services Web en C#. Nous discutons ici d'une introduction aux services Web en C# avec l'utilisation de la technologie, ses limitations et des exemples.

Java Made Simple : Guide du débutant sur la puissance de programmation Introduction Java est un langage de programmation puissant utilisé dans tout, des applications mobiles aux systèmes d'entreprise. Pour les débutants, la syntaxe de Java est simple et facile à comprendre, ce qui en fait un choix idéal pour apprendre la programmation. Syntaxe de base Java utilise un paradigme de programmation orienté objet basé sur les classes. Les classes sont des modèles qui organisent ensemble les données et les comportements associés. Voici un exemple simple de classe Java : publicclassPerson{privateStringname;privateintage;

Java est un langage de programmation populaire qui peut être appris aussi bien par les développeurs débutants que par les développeurs expérimentés. Ce didacticiel commence par les concepts de base et progresse vers des sujets avancés. Après avoir installé le kit de développement Java, vous pouvez vous entraîner à la programmation en créant un simple programme « Hello, World ! ». Une fois que vous avez compris le code, utilisez l'invite de commande pour compiler et exécuter le programme, et « Hello, World ! » s'affichera sur la console. L'apprentissage de Java commence votre parcours de programmation et, à mesure que votre maîtrise s'approfondit, vous pouvez créer des applications plus complexes.
