私はいつもC++を最も強く型付けされた言語の1つだと考えてきました。
それで、私はかなりショックを受けましたこの論文の表 C++が弱い型付けであると述べました。
どうやら、
CおよびC++は、型キャストにより、整数であった構造体のフィールドをポインターとして解釈できるため、弱い型付けと見なされます。
型キャストの存在が重要ですか?そのようなキャストの明示性は重要ではありませんか?
より一般的には、C++が弱い型付けであることが本当に一般的に受け入れられていますか?どうして?
その論文は最初に主張します:
対照的に、型の混乱がサイレントに発生する可能性がある場合(検出されない場合)、言語は弱く型付けされ、最終的にはローカライズが困難なエラーを引き起こします。
そして主張する:
また、CおよびC++は、型キャストにより、整数であった構造体のフィールドをポインターとして解釈できるため、弱い型付けと見なされます。
これは私には矛盾しているように思えます。 CおよびC++では、キャストの結果として発生する可能性のある型の混乱はサイレントに発生しません-キャストがあります!これは、少なくともその論文の定義では、これらの言語のいずれかが弱いタイプであることを示していません。
とは言うものの、この論文の定義によれば、CとC++ mayはまだ弱い型と見なされています。すでに質問のコメントに記載されているように、言語が暗黙的な型変換をサポートしている場合があります。多くの型は暗黙的にbool
に変換でき、型int
のリテラルゼロはサイレントに任意のポインタ型に変換できます。さまざまなサイズの整数間で変換が行われるため、これは論文の目的のためにCとC++を弱く型付けされていると考える正当な理由。
C(C++ではない)の場合、言及する価値のある、より危険な暗黙の変換もあります。
int main() {
int i = 0;
void *v = &i;
char *c = v;
return *c;
}
この論文の目的上、それは間違いなく弱いタイプと見なされなければなりません。ビットの再解釈はサイレントに行われ、完全に無関係なタイプを使用するように変更することでさらに悪化する可能性があります。これは、通常ビットの再解釈と同じ効果を持つサイレントな未定義の動作を持ちますが、最適化が有効になっていると、不思議でありながら面白い方法で爆発します。 。
ただし、一般的に、「強い型」と「弱い型」の定義は決まっていないと思います。さまざまなグレードがありますが、アセンブリに比べて強く型付けされている言語は、パスカルに比べて弱く型付けされている可能性があります。 CまたはC++のどちらが弱い型付けであるかを判断するには、最初に弱い型付けが何を意味するのかを尋ねる必要があります。
"弱いタイプ"は非常に主観的な用語です。 "厳密に型付けされた"および"静的に型付けされた"対"緩く型付けされた"および"動的に型付けされた"、より客観的で、より正確な単語だからです。
私の知る限り、人々は一般的に「弱いタイプ」を「この言語のタイプの概念が好きではない」という意味の小辞的な用語として使用します。これは、特定の言語に対して専門的または技術的な議論を提起できない人にとっては、一種の人身攻撃(または、argumentum ad linguam)です。
「厳密に型指定された」という用語も、わずかに異なる解釈を持っています。私の経験では、一般的に受け入れられている意味は、「型が一致しない場合、コンパイラーはエラーを生成する」です。別の解釈は、「暗黙の変換がないか、ほとんどない」というものです。 これに基づいて、C++は実際には厳密に型指定された言語と見なすことができ、ほとんどの場合、そのように見なされます。 C++に関する一般的なコンセンサスは、それがisであると言えます。厳密に型指定された言語。
もちろん、質問に対してより微妙なアプローチを試して、言語の一部は厳密に型指定され(これはほとんどの場合)、他の部分は緩く型指定されている(算術変換や4つの型などのいくつかの暗黙的な変換)と言うことができます明示的な変換の)。
さらに、一部のプログラマー、特に少数の言語に精通していない初心者が、「厳密」と「静的」、「緩い」と「動的」を区別することを意図していないか、区別できない場合があります。そして、限られた経験に基づいて、2つの(そうでなければ直交する)概念を混同します(通常、たとえば、一般的なスクリプト言語でのダイナミズムと緩いタイピングの相関関係)。
実際には、C++(仮想呼び出し)の一部では、型システムが部分的に動的である必要がありますが、標準の他のものでは厳密である必要があります。繰り返しますが、これらは直交する概念であるため、これは問題ではありません。
要約すると、おそらく言語は完全に、完全にあるカテゴリまたは別のカテゴリに適合しませんが、特定の言語のどの特定のプロパティが支配的であるかを言うことができます。 C++では、厳密さが確実に支配的です。
対照的に、型の混乱がサイレントに発生する可能性がある場合(検出されない場合)、言語は弱く型付けされ、最終的にはローカライズが困難なエラーを引き起こします。
それは、C++で発生する可能性があります。例:
#define _USE_MATH_DEFINES
#include <iostream>
#include <cmath>
#include <limits>
void f(char n) { std::cout << "f(char)\n"; }
void f(int n) { std::cout << "f(int)\n"; }
void g(int n) { std::cout << "f(int)\n"; }
int main()
{
float fl = M_PI; // silent conversion to float may lose precision
f(8 + '0'); // potentially unintended treatment as int
unsigned n = std::numeric_limits<unsigned>::max();
g(n); // potentially unintended treatment as int
}
また、CおよびC++は、型キャストにより、整数であった構造体のフィールドをポインターとして解釈できるため、弱い型付けと見なされます。
うーん...暗黙の変換ではないので、それはばかげた議論です。 C++では型間の明示的なキャストが可能ですが、それが「弱い」ことはほとんどありません。上記のサイト独自の定義で要求されているように、偶発的/サイレントに発生することはありません。
型キャストの存在が重要ですか?そのようなキャストの明示性は重要ではありませんか?
明示性は私見の重要な考慮事項です。プログラマーにコンパイラーの型に関する知識をオーバーライドさせることは、C++の「強力な」機能の1つであり、弱点ではありません。誤って使用することはありません。
より一般的には、C++が弱い型付けであることが本当に一般的に受け入れられていますか?どうして?
いいえ-受け入れられないと思います。 C++は適度に強く型付けされており、void*
から他のポインター型への暗黙的なキャストや、explicit
キャスト演算子とコンストラクターによるよりきめ細かい制御など、歴史的に問題を引き起こしてきた寛大な方法が排除されています。 。
さて、C++の作成者であるBjarneStroustrupは、C++プログラミング言語(第4版)で、言語は強く型付けされていると言っているので、私は彼の言葉を受け入れます。
C++プログラミングは強力な静的型チェックに基づいており、ほとんどの手法は、プログラマーのアイデアの高レベルの抽象化と直接表現を実現することを目的としています。これは通常、低レベルの手法と比較して、実行時とスペースの効率を損なうことなく実行できます。 C++の利点を得るには、別の言語からC++にアクセスするプログラマーは、慣用的なC++プログラミングスタイルと手法を学習して内部化する必要があります。同じことが、以前の表現力の低いバージョンのC++に慣れているプログラマーにも当てはまります。
1994年のこのビデオ講義で、彼はまた、Cの弱い型システムが本当に彼を悩ませていると述べています。そのため、彼はC++を強く型付けしました:C++の設計、Bjarneによる講義Stroustrup