Jump to content

Си (язык программирования)

Страница защищена ожидающими изменениями
(Перенаправлено с языка программирования C )

С
Текст гласит: «Язык программирования C».
Логотип, использованный на обложке первого издания The C Programming Language. [1]
Парадигма Мультипарадигмальность : императивная ( процедурная ), структурированная.
Разработано Деннис Ричи
Разработчик ANSI X3J11 ( ANSI C ); ISO/IEC JTC 1 (Объединенный технический комитет 1) / SC 22 (Подкомитет 22) / WG 14 (Рабочая группа 14) (ISO C)
Впервые появился 1972 год ; 52 года назад ( 1972 ) [2]
Stable release
C17 / June 2018; 6 years ago (2018-06)
Preview release
C23 (N3220) / February 21, 2024; 4 months ago (2024-02-21)[3]
Typing disciplineStatic, weak, manifest, nominal
OSCross-platform
Filename extensions.c, .h
Websitewww.iso.org/standard/74528.html
www.open-std.org/jtc1/sc22/wg14/
Major implementations
pcc, GCC, Clang, Intel C, C++Builder, Microsoft Visual C++, Watcom C
Dialects
Cyclone, Unified Parallel C, Split-C, Cilk, C*
Influenced by
B (BCPL, CPL), ALGOL 68,[4] PL/I, FORTRAN
Influenced
Numerous: AMPL, AWK, csh, C++, C--, C#, Objective-C, D, Go, Java, JavaScript, JS++, Julia, Limbo, LPC, Perl, PHP, Pike, Processing, Python, Rust, Seed7, V (Vlang), Vala, Verilog (HDL),[5] Nim, Zig

C ( произносится / ˈ s / – как буква c ) [6] язык программирования общего назначения . Он был создан в 1970-х годах Деннисом Ритчи и остается очень широко используемым и влиятельным. По замыслу функции C четко отражают возможности целевых процессоров. Он нашел прочное применение в операционных систем коде (особенно в ядрах) . [7] ), драйверы устройств и стеки протоколов , но его использование в прикладном программном обеспечении сокращается. [8] C обычно используется в компьютерных архитектурах, от крупнейших суперкомпьютеров до самых маленьких микроконтроллеров и встроенных систем .

Преемник языка программирования B , C был первоначально разработан в Bell Labs Ритчи между 1972 и 1973 годами для создания утилит, работающих на Unix . Он был применен для повторной реализации ядра операционной системы Unix. [9] В 1980-е годы C постепенно набирал популярность. Он стал одним из наиболее широко используемых языков программирования. [10] [11] с компиляторами C, доступными практически для всех современных компьютерных архитектур и операционных систем. Книга «Язык программирования C» , соавтором которой является первоначальный разработчик языка, в течение многих лет служила фактическим стандартом для языка. [12][1] C стандартизируется с 1989 года Американским национальным институтом стандартов (ANSI), а затем совместно Международной организацией по стандартизации (ISO) и Международной электротехнической комиссией (IEC).

C is an imperative procedural language, supporting structured programming, lexical variable scope, and recursion, with a static type system. It was designed to be compiled to provide low-level access to memory and language constructs that map efficiently to machine instructions, all with minimal runtime support. Despite its low-level capabilities, the language was designed to encourage cross-platform programming. A standards-compliant C program written with portability in mind can be compiled for a wide variety of computer platforms and operating systems with few changes to its source code.

Since 2000, C has consistently ranked among the top two languages in the TIOBE index, a measure of the popularity of programming languages.[13]

Overview[edit]

Dennis Ritchie (right), the inventor of the C programming language, with Ken Thompson

C is an imperative, procedural language in the ALGOL tradition. It has a static type system. In C, all executable code is contained within subroutines (also called "functions", though not in the sense of functional programming). Function parameters are passed by value, although arrays are passed as pointers, i.e. the address of the first item in the array. Pass-by-reference is simulated in C by explicitly passing pointers to the thing being referenced.

C program source text is free-form code. Semicolons terminate statements, while curly braces are used to group statements into blocks.

The C language also exhibits the following characteristics:

  • The language has a small, fixed number of keywords, including a full set of control flow primitives: if/else, for, do/while, while, and switch. User-defined names are not distinguished from keywords by any kind of sigil.
  • It has a large number of arithmetic, bitwise, and logic operators: +,+=,++,&,||, etc.
  • More than one assignment may be performed in a single statement.
  • Functions:
    • Function return values can be ignored, when not needed.
    • Function and data pointers permit ad hoc run-time polymorphism.
    • Functions may not be defined within the lexical scope of other functions.
    • Variables may be defined within a function, with scope.
    • A function may call itself, so recursion is supported.
  • Data typing is static, but weakly enforced; all data has a type, but implicit conversions are possible.
  • User-defined (typedef) and compound types are possible.
    • Heterogeneous aggregate data types (struct) allow related data elements to be accessed and assigned as a unit. The contents of whole structs cannot be compared using a single built-in operator (the elements must be compared individually).
    • Union is a structure with overlapping members; it allows multiple data types to share the same memory location.
    • Array indexing is a secondary notation, defined in terms of pointer arithmetic. Whole arrays cannot be assigned or compared using a single built-in operator. There is no "array" keyword in use or definition; instead, square brackets indicate arrays syntactically, for example month[11].
    • Enumerated types are possible with the enum keyword. They are freely interconvertible with integers.
    • Strings are not a distinct data type, but are conventionally implemented as null-terminated character arrays.
  • Low-level access to computer memory is possible by converting machine addresses to pointers.
  • Procedures (subroutines not returning values) are a special case of function, with an empty return type void.
  • Memory can be allocated to a program with calls to library routines.
  • A preprocessor performs macro definition, source code file inclusion, and conditional compilation.
  • There is a basic form of modularity: files can be compiled separately and linked together, with control over which functions and data objects are visible to other files via static and extern attributes.
  • Complex functionality such as I/O, string manipulation, and mathematical functions are consistently delegated to library routines.
  • The generated code after compilation has relatively straightforward needs on the underlying platform, which makes it suitable for creating operating systems and for use in embedded systems.

While C does not include certain features found in other languages (such as object orientation and garbage collection), these can be implemented or emulated, often through the use of external libraries (e.g., the GLib Object System or the Boehm garbage collector).

Relations to other languages[edit]

Many later languages have borrowed directly or indirectly from C, including C++, C#, Unix's C shell, D, Go, Java, JavaScript (including transpilers), Julia, Limbo, LPC, Objective-C, Perl, PHP, Python, Ruby, Rust, Swift, Verilog and SystemVerilog (hardware description languages).[5] These languages have drawn many of their control structures and other basic features from C. Most of them also express highly similar syntax to C, and they tend to combine the recognizable expression and statement syntax of C with underlying type systems, data models, and semantics that can be radically different.

History[edit]

Early developments[edit]

Timeline of C language
Year Informal
name
Official
standard
1972 first release
1978 K&R C
1989,
1990
ANSI C, C89,
ISO C, C90
ANSI X3.159-1989
ISO/IEC 9899:1990
1999 C99, C9X ISO/IEC 9899:1999
2011 C11, C1X ISO/IEC 9899:2011
2018 C17 ISO/IEC 9899:2018
2024 C23, C2X ISO/IEC 9899:2024
Future C2Y

The origin of C is closely tied to the development of the Unix operating system, originally implemented in assembly language on a PDP-7 by Dennis Ritchie and Ken Thompson, incorporating several ideas from colleagues. Eventually, they decided to port the operating system to a PDP-11. The original PDP-11 version of Unix was also developed in assembly language.[9]

B[edit]

Thompson wanted a programming language for developing utilities for the new platform. At first he tried to write a Fortran compiler, but he soon gave up the idea. Instead, he created a cut-down version of the recently developed systems programming language called BCPL. The official description of BCPL was not available at the time,[14] and Thompson modified the syntax to be less wordy and similar to a simplified ALGOL known as SMALGOL.[15] Thompson called the result B.[9] He described B as "BCPL semantics with a lot of SMALGOL syntax".[15] Like BCPL, B had a bootstrapping compiler to facilitate porting to new machines.[15] However, few utilities were ultimately written in B because it was too slow and could not take advantage of PDP-11 features such as byte addressability.

New B and first C release[edit]

In 1971, Ritchie started to improve B, to utilise the features of the more-powerful PDP-11. A significant addition was a character data type. He called this New B (NB).[15] Thompson started to use NB to write the Unix kernel, and his requirements shaped the direction of the language development.[15][16] Through to 1972, richer types were added to the NB language: NB had arrays of int and char. Pointers, the ability to generate pointers to other types, arrays of all types, and types to be returned from functions were all also added. Arrays within expressions became pointers. A new compiler was written, and the language was renamed C.[9]

The C compiler and some utilities made with it were included in Version 2 Unix, which is also known as Research Unix.[17]

Structures and Unix kernel re-write[edit]

At Version 4 Unix, released in November 1973, the Unix kernel was extensively re-implemented in C.[9] By this time, the C language had acquired some powerful features such as struct types.

The preprocessor was introduced around 1973 at the urging of Alan Snyder and also in recognition of the usefulness of the file-inclusion mechanisms available in BCPL and PL/I. Its original version provided only included files and simple string replacements: #include and #define of parameterless macros. Soon after that, it was extended, mostly by Mike Lesk and then by John Reiser, to incorporate macros with arguments and conditional compilation.[9]

Unix was one of the first operating system kernels implemented in a language other than assembly. Earlier instances include the Multics system (which was written in PL/I) and Master Control Program (MCP) for the Burroughs B5000 (which was written in ALGOL) in 1961. In around 1977, Ritchie and Stephen C. Johnson made further changes to the language to facilitate portability of the Unix operating system. Johnson's Portable C Compiler served as the basis for several implementations of C on new platforms.[16]

K&R C[edit]

The cover of the book The C Programming Language, first edition, by Brian Kernighan and Dennis Ritchie

In 1978, Brian Kernighan and Dennis Ritchie published the first edition of The C Programming Language.[18] Known as K&R from the initials of its authors, the book served for many years as an informal specification of the language. The version of C that it describes is commonly referred to as "K&R C". As this was released in 1978, it is now also referred to as C78.[19] The second edition of the book[20] covers the later ANSI C standard, described below.

K&R introduced several language features:

  • Standard I/O library
  • long int data type
  • unsigned int data type
  • Compound assignment operators of the form =op (such as =-) were changed to the form op= (that is, -=) to remove the semantic ambiguity created by constructs such as i=-10, which had been interpreted as i =- 10 (decrement i by 10) instead of the possibly intended i = -10 (let i be −10).

Even after the publication of the 1989 ANSI standard, for many years K&R C was still considered the "lowest common denominator" to which C programmers restricted themselves when maximum portability was desired, since many older compilers were still in use, and because carefully written K&R C code can be legal Standard C as well.

In early versions of C, only functions that return types other than int must be declared if used before the function definition; functions used without prior declaration were presumed to return type int.

For example:

long some_function(); /* This is a function declaration, so the compiler can know the name and return type of this function. */
/* int */ other_function(); /* Another function declaration.  Because this is an early version of C, there is an implicit 'int' type here.  A comment shows where the explicit 'int' type specifier would be required in later versions. */

/* int */ calling_function() /* This is a function definition, including the body of the code following in the { curly brackets }. Because no return type is specified, the function implicitly returns an 'int' in this early version of C. */
{
    long test1;
    register /* int */ test2; /* Again, note that 'int' is not required here. The 'int' type specifier */
                              /* in the comment would be required in later versions of C. */
                              /* The 'register' keyword indicates to the compiler that this variable should */
                              /* ideally be stored in a register as opposed to within the stack frame. */
    test1 = some_function();
    if (test1 > 1)
          test2 = 0;
    else
          test2 = other_function();
    return test2;
}

The int type specifiers which are commented out could be omitted in K&R C, but are required in later standards.

Since K&R function declarations did not include any information about function arguments, function parameter type checks were not performed, although some compilers would issue a warning message if a local function was called with the wrong number of arguments, or if different calls to an external function used different numbers or types of arguments. Separate tools such as Unix's lint utility were developed that (among other things) could check for consistency of function use across multiple source files.

In the years following the publication of K&R C, several features were added to the language, supported by compilers from AT&T (in particular PCC[21]) and some other vendors. These included:

  • void functions (i.e., functions with no return value)
  • functions returning struct or union types (previously only a single pointer, integer or float could be returned)
  • assignment for struct data types
  • enumerated types (previously, preprocessor definitions for integer fixed values were used, e.g. #define GREEN 3)

The large number of extensions and lack of agreement on a standard library, together with the language popularity and the fact that not even the Unix compilers precisely implemented the K&R specification, led to the necessity of standardization.[citation needed]

ANSI C and ISO C[edit]

During the late 1970s and 1980s, versions of C were implemented for a wide variety of mainframe computers, minicomputers, and microcomputers, including the IBM PC, as its popularity began to increase significantly.

In 1983, the American National Standards Institute (ANSI) formed a committee, X3J11, to establish a standard specification of C. X3J11 based the C standard on the Unix implementation; however, the non-portable portion of the Unix C library was handed off to the IEEE working group 1003 to become the basis for the 1988 POSIX standard. In 1989, the C standard was ratified as ANSI X3.159-1989 "Programming Language C". This version of the language is often referred to as ANSI C, Standard C, or sometimes C89.

In 1990, the ANSI C standard (with formatting changes) was adopted by the International Organization for Standardization (ISO) as ISO/IEC 9899:1990, which is sometimes called C90. Therefore, the terms "C89" and "C90" refer to the same programming language.

ANSI, like other national standards bodies, no longer develops the C standard independently, but defers to the international C standard, maintained by the working group ISO/IEC JTC1/SC22/WG14. National adoption of an update to the international standard typically occurs within a year of ISO publication.

One of the aims of the C standardization process was to produce a superset of K&R C, incorporating many of the subsequently introduced unofficial features. The standards committee also included several additional features such as function prototypes (borrowed from C++), void pointers, support for international character sets and locales, and preprocessor enhancements. Although the syntax for parameter declarations was augmented to include the style used in C++, the K&R interface continued to be permitted, for compatibility with existing source code.

C89 is supported by current C compilers, and most modern C code is based on it. Any program written only in Standard C and without any hardware-dependent assumptions will run correctly on any platform with a conforming C implementation, within its resource limits. Without such precautions, programs may compile only on a certain platform or with a particular compiler, due, for example, to the use of non-standard libraries, such as GUI libraries, or to a reliance on compiler- or platform-specific attributes such as the exact size of data types and byte endianness.

In cases where code must be compilable by either standard-conforming or K&R C-based compilers, the __STDC__ macro can be used to split the code into Standard and K&R sections to prevent the use on a K&R C-based compiler of features available only in Standard C.

After the ANSI/ISO standardization process, the C language specification remained relatively static for several years. In 1995, Normative Amendment 1 to the 1990 C standard (ISO/IEC 9899/AMD1:1995, known informally as C95) was published, to correct some details and to add more extensive support for international character sets.[22]

C99[edit]

The C standard was further revised in the late 1990s, leading to the publication of ISO/IEC 9899:1999 in 1999, which is commonly referred to as "C99". It has since been amended three times by Technical Corrigenda.[23]

C99 introduced several new features, including inline functions, several new data types (including long long int and a complex type to represent complex numbers), variable-length arrays and flexible array members, improved support for IEEE 754 floating point, support for variadic macros (macros of variable arity), and support for one-line comments beginning with //, as in BCPL or C++. Many of these had already been implemented as extensions in several C compilers.

C99 is for the most part backward compatible with C90, but is stricter in some ways; in particular, a declaration that lacks a type specifier no longer has int implicitly assumed. A standard macro __STDC_VERSION__ is defined with value 199901L to indicate that C99 support is available. GCC, Solaris Studio, and other C compilers now[when?] support many or all of the new features of C99. The C compiler in Microsoft Visual C++, however, implements the C89 standard and those parts of C99 that are required for compatibility with C++11.[24][needs update]

In addition, the C99 standard requires support for identifiers using Unicode in the form of escaped characters (e.g. \u0040 or \U0001f431) and suggests support for raw Unicode names.

C11[edit]

In 2007, work began on another revision of the C standard, informally called "C1X" until its official publication of ISO/IEC 9899:2011 on 2011-12-08. The C standards committee adopted guidelines to limit the adoption of new features that had not been tested by existing implementations.

The C11 standard adds numerous new features to C and the library, including type generic macros, anonymous structures, improved Unicode support, atomic operations, multi-threading, and bounds-checked functions. It also makes some portions of the existing C99 library optional, and improves compatibility with C++. The standard macro __STDC_VERSION__ is defined as 201112L to indicate that C11 support is available.

C17[edit]

Published in June 2018 as ISO/IEC 9899:2018, C17 is the current standard for the C programming language. It introduces no new language features, only technical corrections, and clarifications to defects in C11. The standard macro __STDC_VERSION__ is defined as 201710L to indicate that C17 support is available.

C23[edit]

C23 is the informal name for the next (after C17) major C language standard revision. It was informally known as "C2X" through most of its development. C23 is expected to be published in early 2024 as ISO/IEC 9899:2024.[25] The standard macro __STDC_VERSION__ is defined as 202311L to indicate that C23 support is available.

C2Y[edit]

C2Y is a temporary informal name for the next major C language standard revision, after C23 (C2X), that is hoped to be released later in the 2020s decade, per the two in "C2Y". An early working draft of C2Y was released in February 2024 as N3220 by the working group ISO/IEC JTC1/SC22/WG14.[26]

Embedded C[edit]

Historically, embedded C programming requires nonstandard extensions to the C language in order to support exotic features such as fixed-point arithmetic, multiple distinct memory banks, and basic I/O operations.

In 2008, the C Standards Committee published a technical report extending the C language[27] to address these issues by providing a common standard for all implementations to adhere to. It includes a number of features not available in normal C, such as fixed-point arithmetic, named address spaces, and basic I/O hardware addressing.

Syntax[edit]

C has a formal grammar specified by the C standard.[28] Line endings are generally not significant in C; however, line boundaries do have significance during the preprocessing phase. Comments may appear either between the delimiters /* and */, or (since C99) following // until the end of the line. Comments delimited by /* and */ do not nest, and these sequences of characters are not interpreted as comment delimiters if they appear inside string or character literals.[29]

C source files contain declarations and function definitions. Function definitions, in turn, contain declarations and statements. Declarations either define new types using keywords such as struct, union, and enum, or assign types to and perhaps reserve storage for new variables, usually by writing the type followed by the variable name. Keywords such as char and int specify built-in types. Sections of code are enclosed in braces ({ and }, sometimes called "curly brackets") to limit the scope of declarations and to act as a single statement for control structures.

As an imperative language, C uses statements to specify actions. The most common statement is an expression statement, consisting of an expression to be evaluated, followed by a semicolon; as a side effect of the evaluation, functions may be called and variables may be assigned new values. To modify the normal sequential execution of statements, C provides several control-flow statements identified by reserved keywords. Structured programming is supported by if ... [else] conditional execution and by do ... while, while, and for iterative execution (looping). The for statement has separate initialization, testing, and reinitialization expressions, any or all of which can be omitted. break and continue can be used within the loop. Break is used to leave the innermost enclosing loop statement and continue is used to skip to its reinitialisation. There is also a non-structured goto statement which branches directly to the designated label within the function. switch selects a case to be executed based on the value of an integer expression. Different from many other languages, control-flow will fall through to the next case unless terminated by a break.

Expressions can use a variety of built-in operators and may contain function calls. The order in which arguments to functions and operands to most operators are evaluated is unspecified. The evaluations may even be interleaved. However, all side effects (including storage to variables) will occur before the next "sequence point"; sequence points include the end of each expression statement, and the entry to and return from each function call. Sequence points also occur during evaluation of expressions containing certain operators (&&, ||, ?: and the comma operator). This permits a high degree of object code optimization by the compiler, but requires C programmers to take more care to obtain reliable results than is needed for other programming languages.

Kernighan and Ritchie say in the Introduction of The C Programming Language: "C, like any other language, has its blemishes. Some of the operators have the wrong precedence; some parts of the syntax could be better."[30] The C standard did not attempt to correct many of these blemishes, because of the impact of such changes on already existing software.

Character set[edit]

The basic C source character set includes the following characters:

Newline indicates the end of a text line; it need not correspond to an actual single character, although for convenience C treats it as one.

Additional multi-byte encoded characters may be used in string literals, but they are not entirely portable. The latest C standard (C11) allows multi-national Unicode characters to be embedded portably within C source text by using \uXXXX or \UXXXXXXXX encoding (where the X denotes a hexadecimal character), although this feature is not yet widely implemented.

The basic C execution character set contains the same characters, along with representations for alert, backspace, and carriage return. Run-time support for extended character sets has increased with each revision of the C standard.

Reserved words[edit]

The following reserved words are case sensitive.

C89 has 32 reserved words, also known as keywords, which are the words that cannot be used for any purposes other than those for which they are predefined:

C99 reserved five more words: (‡ is an alternative spelling alias for a C23 keyword)

C11 reserved seven more words:[31] (‡ is an alternative spelling alias for a C23 keyword)

  • _Alignas
  • _Alignof
  • _Atomic
  • _Generic
  • _Noreturn
  • _Static_assert
  • _Thread_local

C23 reserved fifteen more words:

  • alignas
  • alignof
  • bool
  • constexpr
  • false
  • nullptr
  • static_assert
  • thread_local
  • true
  • typeof
  • typeof_unqual
  • _BitInt
  • _Decimal32
  • _Decimal64
  • _Decimal128

Most of the recently reserved words begin with an underscore followed by a capital letter, because identifiers of that form were previously reserved by the C standard for use only by implementations. Since existing program source code should not have been using these identifiers, it would not be affected when C implementations started supporting these extensions to the programming language. Some standard headers do define more convenient synonyms for underscored identifiers. Some of those words were added as keywords with their conventional spelling in C23 and the corresponding macros were removed.

Prior to C89, entry was reserved as a keyword. In the second edition of their book The C Programming Language, which describes what became known as C89, Kernighan and Ritchie wrote, "The ... [keyword] entry, formerly reserved but never used, is no longer reserved." and "The stillborn entry keyword is withdrawn."[32]

Operators[edit]

C supports a rich set of operators, which are symbols used within an expression to specify the manipulations to be performed while evaluating that expression. C has operators for:

C uses the operator = (used in mathematics to express equality) to indicate assignment, following the precedent of Fortran and PL/I, but unlike ALGOL and its derivatives. C uses the operator == to test for equality. The similarity between these two operators (assignment and equality) may result in the accidental use of one in place of the other, and in many cases, the mistake does not produce an error message (although some compilers produce warnings). For example, the conditional expression if (a == b + 1) might mistakenly be written as if (a = b + 1), which will be evaluated as true unless the value of a is 0 after the assignment.[33]

The C operator precedence is not always intuitive. For example, the operator == binds more tightly than (is executed prior to) the operators & (bitwise AND) and | (bitwise OR) in expressions such as x & 1 == 0, which must be written as (x & 1) == 0 if that is the coder's intent.[34]

Пример «Привет, мир» [ править ]

"Привет, мир!" программа Брайана Кернигана (1978)

Пример « hello, world », появившийся в первом издании K&R , стал образцом вводной программы в большинстве учебников по программированию. Программа выводит «привет, мир» на стандартный вывод , который обычно представляет собой терминал или экран.

Оригинальная версия была: [35]

main()
{
    printf("hello, world\n");
}

Соответствующая стандарту программа «Привет, мир»: [а]

#include <stdio.h>

int main(void)
{
    printf("hello, world\n");
}

Первая строка программы содержит директиву предварительной обработки , обозначенную #include. Это приводит к тому, что компилятор заменяет эту строку всем текстом stdio.h стандартный заголовок, который содержит объявления для стандартных функций ввода и вывода, таких как printf и scanf. Угловые скобки, окружающие stdio.h указать, что stdio.h можно найти с помощью стратегии поиска, которая предпочитает заголовки, предоставленные компилятором, другим заголовкам с тем же именем, в отличие от двойных кавычек, которые обычно включают локальные или специфичные для проекта файлы заголовков.

Следующая строка указывает, что функция с именем main определяется. main функция служит специальной цели в программах на языке C; среда выполнения вызывает main функция для начала выполнения программы. Спецификатор типа int указывает, что значение, возвращаемое вызывающей стороне (в данном случае среде выполнения) в результате оценки main функция, является целым числом. Ключевое слово void поскольку список параметров указывает, что эта функция не принимает аргументов. [б]

Открывающая фигурная скобка указывает на начало определения main функция.

Следующая строка вызывает (перенаправляет выполнение) функцию с именем printf, который в данном случае предоставляется из системной библиотеки . В этом звонке printf функции передается (предоставляется) один аргумент — адрес первого символа строкового литерала. "hello, world\n". Строковый литерал представляет собой безымянный массив с элементами типа char, автоматически устанавливается компилятором с последним символом NULL (значение ASCII 0) для обозначения конца массива (для printf чтобы узнать длину строки). Символ NULL также можно записать как escape-последовательность , записанную как \0. \n — это escape-последовательность , которую C преобразует в символ новой строки , который на выходе означает конец текущей строки. Возвращаемое значение printf функция имеет тип int, но он молча отбрасывается, поскольку не используется. (Более осторожная программа могла бы проверить возвращаемое значение, чтобы определить, действительно ли printf функция завершилась успешно.) Точка с запятой ; завершает заявление.

Закрывающая фигурная скобка указывает на конец кода для main функция. Согласно спецификации C99 и новее, main функция, в отличие от любой другой функции, неявно возвращает значение 0 по достижении } это завершает функцию. (Раньше явное return 0; требовался оператор.) Это интерпретируется системой времени выполнения как код выхода, указывающий на успешное выполнение. [36]

Типы данных [ править ]

Система типов в C статична и слабо типизирована , что делает ее похожей на систему типов потомков АЛГОЛА, таких как Паскаль . [37] Существуют встроенные типы для целых чисел различных размеров, как знаковых, так и беззнаковых, чисел с плавающей запятой и перечислимых типов ( enum). Целочисленный тип char часто используется для однобайтовых символов. В C99 добавлен логический тип данных . Существуют также производные типы, включая массивы , указатели , записи ( struct) и союзы ( union).

C часто используется в системном программировании низкого уровня, где может потребоваться выход из системы типов. Компилятор пытается обеспечить правильность типов большинства выражений, но программист может переопределить проверки различными способами: либо с помощью приведения типа для явного преобразования значения из одного типа в другой, либо с помощью указателей или объединений для повторной интерпретации базовых битов. объекта данных каким-либо другим способом.

Некоторые считают синтаксис объявления C неинтуитивным, особенно для указателей на функции . (Идея Ричи заключалась в том, чтобы объявлять идентификаторы в контексте, напоминающем их использование: « объявление отражает использование ».) [38]

C Обычные арифметические преобразования позволяют генерировать эффективный код, но иногда могут давать неожиданные результаты. Например, сравнение целых чисел со знаком и без знака одинаковой ширины требует преобразования значения со знаком в беззнаковое. Это может привести к неожиданным результатам, если значение со знаком отрицательно.

Указатели [ править ]

C поддерживает использование указателей — типа ссылки , которая записывает адрес или расположение объекта или функции в памяти. Указатели можно разыменовать для доступа к данным, хранящимся по указанному адресу, или для вызова указанной функции. Указателями можно манипулировать с помощью присваивания или арифметики указателей . Представление значения указателя во время выполнения обычно представляет собой необработанный адрес памяти (возможно, дополненный полем смещения внутри слова), но поскольку тип указателя включает тип объекта, на который он указывает, выражения, включающие указатели, могут быть проверены по типу. во время компиляции. Арифметика указателей автоматически масштабируется в соответствии с размером типа данных, на который указывает.

Указатели используются в C для многих целей. Текстовые строки обычно обрабатываются с помощью указателей на массивы символов. Динамическое выделение памяти осуществляется с помощью указателей; результат malloc обычно приводится к типу сохраняемых данных. Многие типы данных, такие как деревья , обычно реализуются как динамически выделяемые. struct объекты, связанные между собой с помощью указателей. Указатели на другие указатели часто используются в многомерных массивах и массивах struct объекты. Указатели на функции ( указатели функций ) полезны для передачи функций в качестве аргументов функциям более высокого порядка (таким как qsort или bsearch ), в таблицах диспетчеризации или в качестве обратных вызовов обработчикам событий . [36]

нулевого указателя Значение явно указывает на отсутствие допустимого местоположения. Разыменование значения нулевого указателя не определено, что часто приводит к ошибке сегментации . Значения нулевого указателя полезны для указания особых случаев, таких как отсутствие указателя «следующий» в конечном узле связанного списка или в качестве индикации ошибки в функциях, возвращающих указатели. В соответствующих контекстах исходного кода, например, при присвоении переменной указателя, константа нулевого указателя может быть записана как 0, с явным приведением к типу указателя или без него, поскольку NULL макрос, определенный несколькими стандартными заголовками или, начиная с C23, с константой nullptr. В условных контекстах значения нулевого указателя оцениваются как false, в то время как все остальные значения указателя оцениваются как true.

Пустые указатели ( void *) указывают на объекты неопределенного типа и поэтому могут использоваться как «универсальные» указатели данных. Поскольку размер и тип объекта, на который указывает указатель, неизвестны, указатели void не могут быть разыменованы, а арифметика указателей на них не допускается, хотя их можно легко (и во многих контекстах неявно так и делают) преобразовать в указатель любого другого объекта и из него. тип. [36]

Неосторожное использование указателей потенциально опасно. Поскольку они обычно не отмечены флажком, переменную-указатель можно указать на любое произвольное место, что может вызвать нежелательные эффекты. Хотя правильно используемые указатели указывают на безопасные места, их можно заставить указывать на небезопасные места, используя недопустимую арифметику указателей ; объекты, на которые они указывают, могут продолжать использоваться после освобождения ( висячие указатели ); их можно использовать без инициализации ( дикие указатели ); или им может быть напрямую присвоено небезопасное значение с помощью приведения, объединения или другого поврежденного указателя. В общем, C позволяет манипулировать типами указателей и преобразовывать их между собой, хотя компиляторы обычно предоставляют опции для различных уровней проверки. Некоторые другие языки программирования решают эти проблемы, используя более ограничительные ссылочные типы.

Массивы [ править ]

Типы массивов в C традиционно имеют фиксированный статический размер, указанный во время компиляции. Более поздний стандарт C99 также допускает использование массивов переменной длины. Однако также возможно выделить блок памяти (произвольного размера) во время выполнения, используя стандартную библиотеку. malloc функцию и рассматривать ее как массив.

Поскольку доступ к массивам (фактически) всегда осуществляется через указатели, доступ к массиву обычно не проверяется по размеру базового массива, хотя некоторые компиляторы могут предоставлять проверку границ в качестве опции. [39] [40] Поэтому возможны нарушения границ массива, которые могут привести к различным последствиям, включая незаконный доступ к памяти, повреждение данных, переполнение буфера и исключения во время выполнения.

В C нет специального средства для объявления многомерных массивов , а скорее полагается на рекурсию внутри системы типов для объявления массивов массивов, что фактически выполняет то же самое. Значения индекса результирующего «многомерного массива» можно рассматривать как увеличивающиеся в порядке возрастания строк . Многомерные массивы обычно используются в числовых алгоритмах (в основном из прикладной линейной алгебры ) для хранения матриц. Структура массива C хорошо подходит для этой конкретной задачи. Однако в ранних версиях C границы массива должны быть известны фиксированными значениями или явно передаваться в любую подпрограмму, которая их требует, а к массивам массивов с динамическим размером нельзя получить доступ с помощью двойной индексации. (Обходным решением этой проблемы было выделение массива с дополнительным «вектором-строкой» указателей на столбцы.) C99 представил «массивы переменной длины», которые решают эту проблему.

В следующем примере с использованием современного C (C99 или более поздней версии) показано размещение двумерного массива в куче и использование индексации многомерного массива для доступа (которая может использовать проверку границ во многих компиляторах C):

int func(int N, int M)
{
  float (*p)[N][M] = malloc(sizeof *p);
  if (p == 0)
    return -1;
  for (int i = 0; i < N; i++)
    for (int j = 0; j < M; j++)
      (*p)[i][j] = i + j;
  print_array(N, M, p);
  free(p);
  return 1;
}

А вот аналогичная реализация с использованием функции Auto VLA C99 : [с]

int func(int N, int M)
{
  // Caution: checks should be made to ensure N*M*sizeof(float) does NOT exceed limitations for auto VLAs and is within available size of stack.
  float p[N][M]; // auto VLA is held on the stack, and sized when the function is invoked
  for (int i = 0; i < N; i++)
    for (int j = 0; j < M; j++)
      p[i][j] = i + j;
  print_array(N, M, p);
  // no need to free(p) since it will disappear when the function exits, along with the rest of the stack frame
  return 1;
}

Взаимозаменяемость массива и указателя [ править ]

Индексное обозначение x[i] (где x обозначает указатель) является синтаксическим сахаром для *(x+i). [41] Воспользовавшись знанием компилятора типа указателя, адреса, который x + i указывает на не базовый адрес (на который указывает x) увеличивается на i байт, а скорее определяется как базовый адрес, увеличенный на i умножается на размер элемента, который x указывает на. Таким образом, x[i] обозначает i+1-й элемент массива.

Более того, в большинстве контекстов выражений (заметным исключением является операнд sizeof), выражение типа массива автоматически преобразуется в указатель на первый элемент массива. Это означает, что массив никогда не копируется целиком, если он назван в качестве аргумента функции, а передается только адрес его первого элемента. Таким образом, хотя вызовы функций в C используют семантику передачи по значению , массивы фактически передаются по ссылке .

Общий размер массива x можно определить, применив sizeof к выражению типа массива. Размер элемента можно определить, применив оператор sizeof к любому разыменованному элементу массива A, как в n = sizeof A[0]. Таким образом, количество элементов в объявленном массиве A может быть определен как sizeof A / sizeof A[0]. Обратите внимание: если доступен только указатель на первый элемент, как это часто бывает в коде C из-за описанного выше автоматического преобразования, информация о полном типе массива и его длине теряется.

Управление памятью [ править ]

Одной из наиболее важных функций языка программирования является предоставление средств управления памятью и объектами, хранящимися в памяти. C предоставляет три основных способа выделения памяти для объектов: [36]

  • Статическое выделение памяти : пространство для объекта предоставляется в двоичном виде во время компиляции; эти объекты имеют размер (или время жизни) до тех пор, пока содержащий их двоичный файл загружается в память.
  • Автоматическое выделение памяти : временные объекты могут храниться в стеке , и это пространство автоматически освобождается и может быть повторно использовано после выхода из блока, в котором они объявлены.
  • Динамическое распределение памяти : блоки памяти произвольного размера могут быть запрошены во время выполнения с использованием библиотечных функций, таких как malloc из области памяти, называемой кучей ; эти блоки сохраняются до тех пор, пока впоследствии не будут освобождены для повторного использования путем вызова библиотечной функции. realloc или free

Эти три подхода подходят в разных ситуациях и имеют различные компромиссы. Например, статическое выделение памяти имеет небольшие накладные расходы, автоматическое выделение может потребовать немного больше накладных расходов, а динамическое выделение памяти потенциально может иметь большие накладные расходы как на выделение, так и на освобождение. Постоянный характер статических объектов полезен для сохранения информации о состоянии во время вызовов функций, автоматическое выделение легко использовать, но пространство стека обычно гораздо более ограничено и преходяще, чем статическая память или пространство кучи, а динамическое распределение памяти позволяет удобно выделять объекты, размер известен только во время выполнения. Большинство программ на языке C широко используют все три.

Там, где это возможно, автоматическое или статическое выделение обычно является самым простым, поскольку хранилищем управляет компилятор, что освобождает программиста от потенциально подверженной ошибкам рутинной работы по выделению и освобождению памяти вручную. Однако размер многих структур данных может изменяться во время выполнения, а поскольку статические выделения (и автоматические выделения до C99) должны иметь фиксированный размер во время компиляции, существует множество ситуаций, в которых динамическое выделение необходимо. [36] До стандарта C99 частым примером были массивы переменного размера. (См. статью о malloc в качестве примера динамически выделяемых массивов.) В отличие от автоматического выделения, которое может привести к сбою во время выполнения с неконтролируемыми последствиями, функции динамического выделения возвращают индикацию (в виде значения нулевого указателя), когда необходимое хранилище не может быть выделено. (Слишком большое статическое выделение обычно обнаруживается компоновщиком или загрузчиком еще до того, как программа сможет начать выполнение.)

Если не указано иное, статические объекты содержат нулевые или нулевые значения указателя при запуске программы. Автоматически и динамически выделяемые объекты инициализируются только в том случае, если начальное значение указано явно; в противном случае они изначально имеют неопределенные значения (обычно это любой битовый шаблон , присутствующий в хранилище , который может даже не представлять допустимое значение для этого типа). Если программа попытается получить доступ к неинициализированному значению, результаты будут неопределенными. Многие современные компиляторы пытаются обнаружить и предупредить об этой проблеме, но могут возникать как ложноположительные, так и ложноотрицательные результаты .

Выделение кучи памяти должно быть синхронизировано с ее фактическим использованием в любой программе, чтобы ее можно было использовать повторно. Например, если единственный указатель на выделение памяти в куче выходит за пределы области действия или его значение перезаписывается до того, как оно будет явно освобождено, то эта память не может быть восстановлена ​​для последующего повторного использования и по существу теряется для программы — явление, известное как память. утечка . И наоборот, память может быть освобождена, но к ней будут обращаться впоследствии, что приведет к непредсказуемым результатам. Обычно симптомы сбоя появляются в части программы, не связанной с кодом, вызывающим ошибку, что затрудняет диагностику сбоя. Такие проблемы решаются в языках с автоматической сборкой мусора .

Библиотеки [ править ]

Язык программирования C использует библиотеки в качестве основного метода расширения. В языке C библиотека — это набор функций, содержащихся в одном «архивном» файле. Каждая библиотека обычно имеет заголовочный файл , который содержит прототипы функций, содержащихся в библиотеке, которые могут использоваться программой, а также объявления специальных типов данных и макросимволов, используемых с этими функциями. Чтобы программа могла использовать библиотеку, она должна включать заголовочный файл библиотеки, а библиотека должна быть связана с программой, что во многих случаях требует флагов компилятора (например, -lm, сокращение от «связать математическую библиотеку»). [36]

Наиболее распространенной библиотекой C является стандартная библиотека C , которая определяется стандартами ISO и ANSI C и поставляется с каждой реализацией C (реализации, предназначенные для ограниченных сред, таких как встроенные системы, могут предоставлять только подмножество стандартной библиотеки). Эта библиотека поддерживает потоковый ввод и вывод, распределение памяти, математические операции, строки символов и значения времени. Несколько отдельных стандартных заголовков (например, stdio.h) определяют интерфейсы для этих и других стандартных библиотечных средств.

Другой распространенный набор функций библиотеки C — это те, которые используются приложениями, специально предназначенными для Unix и Unix-подобных систем, особенно функции, которые обеспечивают интерфейс с ядром . Эти функции подробно описаны в различных стандартах, таких как POSIX и Единая спецификация UNIX .

Поскольку многие программы написаны на языке C, существует множество других доступных библиотек. Библиотеки часто пишутся на C, поскольку компиляторы C генерируют эффективный объектный код ; затем программисты создают интерфейсы для библиотеки, чтобы подпрограммы можно было использовать из языков более высокого уровня, таких как Java , Perl и Python . [36]

Обработка файлов и потоки [ править ]

Ввод и вывод файлов (I/O) не являются частью самого языка C, а обрабатываются библиотеками (такими как стандартная библиотека C) и связанными с ними заголовочными файлами (например, stdio.h). Обработка файлов обычно реализуется посредством ввода-вывода высокого уровня, который работает через потоки . С этой точки зрения поток — это поток данных, независимый от устройств, тогда как файл — это конкретное устройство. Ввод-вывод высокого уровня осуществляется посредством ассоциации потока с файлом. В стандартной библиотеке C буфер (область памяти или очередь) временно используется для хранения данных перед их отправкой в ​​конечный пункт назначения. Это сокращает время ожидания более медленных устройств, например жесткого или твердотельного накопителя . Функции ввода-вывода низкого уровня не являются частью стандартной библиотеки C. [ нужны разъяснения ] но, как правило, являются частью программирования на «голом железе» (программирование, независимое от какой-либо операционной системы, например, большинство встроенных программ ). За некоторыми исключениями, реализации включают низкоуровневый ввод-вывод.

Языковые инструменты [ править ]

Был разработан ряд инструментов, помогающих программистам на C находить и исправлять операторы с неопределенным поведением или, возможно, ошибочными выражениями, с большей строгостью, чем та, которую обеспечивает компилятор. Инструмент lint был первым подобным инструментом, за которым последовало множество других.

Автоматизированная проверка и аудит исходного кода полезны на любом языке, и для C существует множество таких инструментов, например Lint . Обычной практикой является использование Lint для обнаружения сомнительного кода при первом написании программы. Как только программа проходит Lint, она компилируется с помощью компилятора C. Кроме того, многие компиляторы могут дополнительно предупреждать о синтаксически допустимых конструкциях, которые на самом деле могут оказаться ошибками. MISRA C — это собственный набор правил, позволяющий избегать использования такого сомнительного кода, разработанный для встроенных систем. [42]

Существуют также компиляторы, библиотеки и механизмы уровня операционной системы для выполнения действий, не являющихся стандартной частью C, таких как проверка границ массивов, обнаружение переполнения буфера , сериализация , отслеживание динамической памяти и автоматическая сборка мусора .

Такие инструменты, как Purify или Valgrind , а также связывание с библиотеками, содержащими специальные версии функций распределения памяти, могут помочь обнаружить ошибки во время выполнения, связанные с использованием памяти. [43] [44]

Использует [ править ]

использования в программировании Обоснование системном

Некоторое программное обеспечение, написанное на C

C широко используется для системного программирования при реализации операционных систем и встроенных системных приложений. [45] Это происходит по нескольким причинам:

  • Язык C обеспечивает доступ к аппаратному обеспечению и памяти платформы с помощью указателей и каламбура типов , поэтому специфичные для системы функции (например, регистры управления/состояния , регистры ввода-вывода ) могут быть настроены и использованы с кодом, написанным на C – это обеспечивает наиболее полный контроль над платформа, на которой он работает.
  • Код, сгенерированный после компиляции, не требует многих системных функций и может быть напрямую вызван из некоторого загрузочного кода — его просто выполнить.
  • Операторы и выражения языка C обычно хорошо сопоставляются с последовательностями инструкций для целевого процессора, и, следовательно, во время выполнения требуется мало системных ресурсов — они выполняются быстро.
  • Благодаря богатому набору операторов язык C может использовать многие функции целевых процессоров. Если конкретный ЦП имеет более экзотические инструкции, можно создать языковой вариант с, возможно, встроенными функциями для использования этих инструкций - он может использовать практически все функции целевого ЦП.
  • Язык позволяет легко накладывать структуры на блоки двоичных данных, позволяя понимать данные, перемещаться по ним и изменять их — он может записывать структуры данных, даже файловые системы.
  • Язык поддерживает богатый набор операторов, включая битовые манипуляции, для целочисленной арифметики и логики, а также, возможно, различные размеры чисел с плавающей запятой — он может эффективно обрабатывать соответствующим образом структурированные данные.
  • C — довольно небольшой язык, содержащий всего несколько операторов и не имеющий слишком большого количества функций, которые генерируют обширный целевой код — он понятен.
  • C имеет прямой контроль над выделением и освобождением памяти, что обеспечивает разумную эффективность и предсказуемое время операций обработки памяти, без каких-либо проблем со спорадическими событиями остановки мира - он имеет предсказуемую производительность.
  • C позволяет использовать и реализовывать различные схемы распределения памяти , включая типичную. malloc и free; более сложный механизм с аренами ; или версию для ядра ОС , которая может подходить для DMA , использоваться в обработчиках прерываний или интегрироваться с системой виртуальной памяти .
  • В зависимости от компоновщика и среды код C также может вызывать библиотеки, написанные на языке ассемблера , и может вызываться из языка ассемблера — он хорошо взаимодействует с другим кодом более низкого уровня.
  • C, его соглашения о вызовах и структуры компоновщика обычно используются в сочетании с другими языками высокого уровня, при этом поддерживаются вызовы как на C, так и из C — он хорошо взаимодействует с другим кодом высокого уровня.
  • C имеет очень зрелую и обширную экосистему, включающую библиотеки, фреймворки, компиляторы с открытым исходным кодом, отладчики и утилиты, и является фактическим стандартом. Вполне вероятно, что драйверы на C уже существуют или существует архитектура ЦП, аналогичная внутренней части компилятора C, поэтому стимулы для выбора другого языка уменьшаются.

Используется для библиотек с интенсивными вычислениями [ править ]

C позволяет программистам создавать эффективные реализации алгоритмов и структур данных, поскольку уровень абстракции от аппаратного обеспечения тонкий, а его накладные расходы невелики, что является важным критерием для программ с интенсивными вычислениями. Например, библиотека арифметики множественной точности GNU , научная библиотека GNU , Mathematica и MATLAB полностью или частично написаны на C. Многие языки поддерживают вызов библиотечных функций на C, например, Python на основе фреймворк NumPy использует C для высокой точности. -Аспекты производительности и взаимодействия с оборудованием.

C как промежуточный язык [ править ]

C иногда используется в качестве промежуточного языка в реализациях других языков. Этот подход можно использовать для портативности или удобства; используя C в качестве промежуточного языка, дополнительные генераторы кода, специфичные для машины, не нужны. В C есть некоторые функции, такие как директивы препроцессора с номерами строк и необязательные лишние запятые в конце списков инициализаторов, которые поддерживают компиляцию сгенерированного кода. Однако некоторые недостатки C побудили разработку других языков на основе C, специально предназначенных для использования в качестве промежуточных языков, таких как C-- . Кроме того, современные основные компиляторы GCC и LLVM имеют промежуточное представление , отличное от C, и эти компиляторы поддерживают интерфейсы для многих языков, включая C.

Другие языки, написанные на C [ править ]

Следствием широкой доступности и эффективности C является то, что компиляторы , библиотеки и интерпретаторы других языков программирования часто реализуются на C. [46] Например, реализации Python эталонные , [47] Перл , [48] Руби , [49] и PHP [50] написаны на языке С.

Когда-то использовался для веб-разработки [ править ]

Исторически C иногда использовался для веб-разработки с использованием Common Gateway Interface (CGI) в качестве «шлюза» для передачи информации между веб-приложением, сервером и браузером. [51] Си, возможно, был предпочтительнее интерпретируемых языков из-за его скорости, стабильности и почти универсальной доступности. [52] Веб-разработка на языке C больше не является обычной практикой. [53] и существует множество других инструментов веб-разработки .

Веб-серверы [ править ]

Два самых популярных веб-сервера , Apache HTTP Server и Nginx , написаны на C. Эти веб-серверы взаимодействуют с операционной системой, прослушивают TCP-порты на предмет HTTP-запросов, а затем обслуживают статический веб-контент или вызывают выполнение других языки, обрабатывающие «рендеринг» контента, такие как PHP , который сам по себе в основном написан на C. «близкий к металлу» подход C позволяет создавать такие высокопроизводительные программные системы.

Приложения для конечных пользователей [ править ]

Язык C также широко используется для реализации приложений для конечных пользователей . [54] Однако такие приложения также можно писать на более новых языках более высокого уровня.

Ограничения [ править ]

мощь языка ассемблера и удобство... языка ассемблера

Деннис Ричи [55]

Хотя C был популярен, влиятельн и чрезвычайно успешен, у него есть недостатки, в том числе:

  • Стандартная обработка динамической памяти с помощью malloc и free подвержен ошибкам. К ошибкам относятся: Утечки памяти, когда память выделяется, но не освобождается; и доступ к ранее освобожденной памяти.
  • Использование указателей и прямое манипулирование памятью означает, что возможно повреждение памяти, возможно, из-за ошибки программиста или недостаточной проверки неверных данных.
  • Существует некоторая проверка типов , но она не применима к таким областям, как вариативные функции , и проверку типов можно тривиально или непреднамеренно обойти. Он слабо типизирован .
  • Поскольку код, сгенерированный компилятором, сам по себе содержит мало проверок, на программиста ложится обязанность учитывать все возможные результаты, защищать от переполнения буфера, проверки границ массива, переполнения стека , исчерпания памяти, а также учитывать условия гонки , изоляцию потоков и т. д. .
  • Использование указателей и манипулирование ими во время выполнения означает, что может быть два способа доступа к одним и тем же данным (псевдонимы), которые невозможно определить во время компиляции. Это означает, что некоторые оптимизации, доступные для других языков, невозможны в C. FORTRAN считается более быстрым.
  • Некоторые функции стандартной библиотеки, например scanf или strncat, может привести к переполнению буфера .
  • Существует ограниченная стандартизация поддержки низкоуровневых вариантов сгенерированного кода, например: различные соглашения о вызове функций и ABI ; различные по упаковке структур соглашения ; различный порядок байтов в больших целых числах (включая порядок байтов). Во многих реализациях языка некоторые из этих параметров могут обрабатываться с помощью директивы препроцессора. #pragma, [56] [57] а некоторые с дополнительными ключевыми словами, например, используйте __cdecl соглашение о вызовах. Но директива и параметры не поддерживаются последовательно. [58]
  • Обработка строк с использованием стандартной библиотеки требует большого количества кода и требует явного управления памятью.
  • Язык напрямую не поддерживает объектную ориентацию, интроспекцию , оценку выражений во время выполнения, дженерики и т. д.
  • Существует мало средств защиты от ненадлежащего использования возможностей языка, которое может привести к неподдерживаемому коду. В частности, препроцессор C может скрывать такие тревожные эффекты, как двойное вычисление и многое другое. [59] Эта возможность создания сложного кода была отмечена такими соревнованиями, как International Obfuscated C Code Contest и Underhanded C Contest .
  • В C отсутствует стандартная поддержка обработки исключений , и он предлагает только коды возврата для проверки ошибок. setjmp и longjmp использовались стандартные библиотечные функции [60] реализовать механизм try-catch с помощью макросов.

Для некоторых целей были приняты ограниченные стили C, например MISRA C или CERT C , в попытке уменьшить вероятность ошибок. Базы данных, такие как CWE, пытаются подсчитать количество уязвимостей C и т. д., а также дать рекомендации по их устранению.

Существуют инструменты , которые могут смягчить некоторые недостатки. Современные компиляторы C включают проверки, которые могут генерировать предупреждения, помогающие выявить множество потенциальных ошибок.

Родственные языки [ править ]

График индекса TIOBE , показывающий сравнение популярности различных языков программирования. [61]

C прямо и косвенно повлиял на многие более поздние языки, такие как C++ и Java . [62] Наиболее распространенное влияние было синтаксическим; все упомянутые языки сочетают в себе синтаксис операторов и (более или менее узнаваемых) выражений C с системами типов, моделями данных или крупномасштабными программными структурами, которые отличаются от C, иногда радикально.

Существует несколько интерпретаторов C или близких к C, включая Ch и CINT , которые также можно использовать для написания сценариев.

Когда объектно-ориентированные языки программирования стали популярными, C++ и Objective-C были двумя разными расширениями C, предоставлявшими объектно-ориентированные возможности. Оба языка изначально были реализованы как компиляторы исходного кода ; исходный код был переведен на C, а затем скомпилирован компилятором C. [63]

Язык программирования C++ (первоначально называвшийся «C с классами ») был разработан Бьярном Страуструпом как подход к обеспечению объектно-ориентированной функциональности с синтаксисом, подобным C. [64] C++ добавляет большую силу типизации, область видимости и другие инструменты, полезные в объектно-ориентированном программировании, а также допускает универсальное программирование с помощью шаблонов. Теперь это почти расширенный набор C, C++. [ когда? ] поддерживает большую часть C, за некоторыми исключениями .

Objective-C изначально был очень «тонким» слоем поверх C и остается строгим надмножеством C, которое позволяет объектно-ориентированное программирование с использованием гибридной парадигмы динамической/статической типизации. Синтаксис Objective-C заимствован как из C, так и из Smalltalk : синтаксис, включающий предварительную обработку, выражения, объявления функций и вызовы функций, унаследован от C, тогда как синтаксис объектно-ориентированных функций изначально был взят из Smalltalk.

Помимо C++ и Objective-C , Ch , Cilk и Unified Parallel C являются почти надмножествами C.

См. также [ править ]

Примечания [ править ]

  1. ^ Исходный код примера будет компилироваться на большинстве современных компиляторов, которые не находятся в режиме строгого соответствия стандартам, но он не полностью соответствует требованиям ни C89, ни C99. Фактически, C99 требует создания диагностического сообщения.
  2. ^ main функция на самом деле имеет два аргумента, int argc и char *argv[]соответственно, которые можно использовать для обработки аргументов командной строки . Стандарт ISO C (раздел 5.1.2.2.1) требует обеих форм main поддерживаться, что представляет собой особый режим, не предоставляемый какой-либо другой функции.
  3. ^ Кодекс print_array (не показан) незначительно отличается, [ почему? ] слишком.

Ссылки [ править ]

  1. Перейти обратно: Перейти обратно: а б Принц, Питер; Кроуфорд, Тони (16 декабря 2005 г.). Коротко о С. О'Рейли Медиа, Инк. с. 3. ISBN  9780596550714 .
  2. ^ Ричи (1993) : «Томпсон предпринял короткую попытку создать систему, закодированную на ранней версии C - до структур - в 1972 году, но отказался от этой попытки».
  3. ^ «N3221 - Отчет редактора, после встречи в Страсбурге, Франция, январь 2024 г.» . ISO/IEC JTC1/SC22/WG14 . Открытые стандарты. 21 февраля 2024 г. . Проверено 24 мая 2024 г.
  4. ^ Ричи (1993) : «Схема композиции типов, принятая C, во многом обязана Алголу 68, хотя, возможно, она не появилась в форме, которую одобрили бы приверженцы Алгола».
  5. Перейти обратно: Перейти обратно: а б «Verilog HDL (и C)» (PDF) . Исследовательская школа компьютерных наук Австралийского национального университета. 3 июня 2010 г. Архивировано из оригинала (PDF) 6 ноября 2013 г. . Проверено 19 августа 2013 г. 1980-е: впервые представлен Verilog; Verilog вдохновлен языком программирования C.
  6. ^ «Имя основано на букве C английского алфавита и произносится как буква C» . звук языка программирования c . Англо-китайский словарь. Архивировано из оригинала 17 ноября 2022 года . Проверено 17 ноября 2022 г.
  7. ^ Муньос, Дэниел. «Спустя все эти годы, мир по-прежнему опирается на программирование на языке C | Toptal®» . Блог Toptal Engineering . Проверено 15 июня 2024 г.
  8. ^ «Рейтинг популярности языка C упал до самого низкого уровня» . Разработчик.com . 9 августа 2016 года. Архивировано из оригинала 22 августа 2022 года . Проверено 1 августа 2022 г.
  9. Перейти обратно: Перейти обратно: а б с д и ж Ричи (1993)
  10. ^ «Популярность языка программирования» . 2009. Архивировано из оригинала 16 января 2009 года . Проверено 16 января 2009 г.
  11. ^ «Индекс сообщества программистов TIOBE» . 2009. Архивировано из оригинала 4 мая 2009 года . Проверено 6 мая 2009 г.
  12. ^ Уорд, Терри А. (август 1983 г.). «Аннотированная C/A библиография языка C» . Байт . п. 268 . Проверено 31 января 2015 г.
  13. ^ «Индекс TIOBE за октябрь 2021 года» . Архивировано из оригинала 25 февраля 2018 года . Проверено 7 октября 2021 г.
  14. ^ Ричи, Деннис. «BCPL от B до C» . Архивировано из оригинала 12 декабря 2019 года . Проверено 10 сентября 2019 г.
  15. Перейти обратно: Перейти обратно: а б с д и Дженсен, Ричард (9 декабря 2020 г.). « Чертовски глупый поступок» — происхождение C» . Арс Техника . Архивировано из оригинала 28 марта 2022 года . Проверено 28 марта 2022 г.
  16. Перейти обратно: Перейти обратно: а б Джонсон, Южная Каролина ; Ричи, DM (1978). «Переносимость программ на языке C и системы UNIX». Белл Систем Тех. Дж . 57 (6): 2021–2048. CiteSeerX   10.1.1.138.35 . дои : 10.1002/j.1538-7305.1978.tb02141.x . S2CID   17510065 . (Примечание. PDF-файл представляет собой сканирование оригинала с помощью оптического распознавания символов и содержит изображение «IBM 370» как «IBM 310».)
  17. ^ Макилрой, доктор медицины (1987). Читатель Research Unix: аннотированные выдержки из Руководства программиста, 1971–1986 (PDF) (Технический отчет). CSTR. Лаборатории Белла. п. 10. 139. Архивировано (PDF) из оригинала 11 ноября 2017 г. . Проверено 1 февраля 2015 г.
  18. ^ Керниган, Брайан В .; Ричи, Деннис М. (февраль 1978 г.). Язык программирования C (1-е изд.). Энглвуд Клиффс, Нью-Джерси : Прентис Холл . ISBN  978-0-13-110163-0 .
  19. ^ «Страницы руководства по C». Руководство по разной информации FreeBSD (изд. FreeBSD 13.0). 30 мая 2011 г. Архивировано из оригинала 21 января 2021 г. Проверено 15 января 2021 г. [1] Архивировано 21 января 2021 г. в Wayback Machine.
  20. ^ Керниган, Брайан В .; Ричи, Деннис М. (март 1988 г.). Язык программирования C (2-е изд.). Энглвуд Клиффс, Нью-Джерси : Прентис Холл . ISBN  978-0-13-110362-7 .
  21. ^ Страуструп, Бьярн (2002). Соперничество между братьями и сестрами: C и C++ (PDF) (Отчет). Лаборатории AT&T. Архивировано (PDF) из оригинала 24 августа 2014 г. Проверено 14 апреля 2014 г.
  22. ^ С Честность . Международная организация по стандартизации. 30 марта 1995 года. Архивировано из оригинала 25 июля 2018 года . Проверено 24 июля 2018 г.
  23. ^ «JTC1/SC22/WG14 – C» . Домашняя страница . ИСО/МЭК. Архивировано из оригинала 12 февраля 2018 года . Проверено 2 июня 2011 г.
  24. ^ Эндрю Бинсток (12 октября 2011 г.). «Интервью с Хербом Саттером» . Доктор Доббс . Архивировано из оригинала 2 августа 2013 года . Проверено 7 сентября 2013 г.
  25. ^ «WG14-N3132: Пересмотренное расписание C23» (PDF) . open-std.org . 4 июня 2023 г. Архивировано (PDF) из оригинала 9 июня 2023 г.
  26. ^ «WG14-N3220: Рабочий проект, C2y» (PDF) . open-std.org . 21 февраля 2024 г. Архивировано (PDF) из оригинала 26 февраля 2024 г.
  27. ^ «TR 18037: Встроенный C» (PDF) . ИСО/МЭК. Архивировано (PDF) из оригинала 25 февраля 2021 г. Проверено 26 июля 2011 г.
  28. ^ Харбисон, Сэмюэл П.; Стил, Гай Л. (2002). C: Справочное руководство (5-е изд.). Энглвуд Клиффс, Нью-Джерси : Прентис Холл . ISBN  978-0-13-089592-9 . Содержит грамматику BNF для C.
  29. ^ Керниган и Ричи (1988) , с. 192.
  30. ^ Керниган и Ричи (1978) , с. 3.
  31. ^ «Проект комитета ISO/IEC 9899:201x (ISO C11)» (PDF) . Архивировано (PDF) из оригинала 22 декабря 2017 г. Проверено 16 сентября 2011 г.
  32. ^ Керниган и Ричи (1988) , стр. 192, 259.
  33. ^ «10 распространенных ошибок программирования на C++» . Cs.ucr.edu. Архивировано из оригинала 21 октября 2008 года . Проверено 26 июня 2009 г.
  34. ^ Шульц, Томас (2004). C и 8051 (3-е изд.). Отсего, Мичиган: PageFree Publishing Inc., с. 20. ISBN  978-1-58961-237-2 . Проверено 10 февраля 2012 г.
  35. ^ Керниган и Ричи (1978) , с. 6.
  36. Перейти обратно: Перейти обратно: а б с д и ж г Клеменс, Бен (2013). 21 век С. О'Рейли Медиа . ISBN  978-1-4493-2714-9 .
  37. ^ Фойер, Алан Р.; Гехани, Нараин Х. (март 1982 г.). «Сравнение языков программирования C и Pascal». Обзоры вычислительной техники ACM . 14 (1): 73–92. дои : 10.1145/356869.356872 . S2CID   3136859 .
  38. ^ Керниган и Ричи (1988) , с. 122.
  39. ^ Например, gcc предоставляет _FORTIFY_SOURCE. «Функции безопасности: проверки буфера времени компиляции (FORTIFY_SOURCE)» . Fedoraproject.org. Архивировано из оригинала 7 января 2007 года . Проверено 5 августа 2012 г.
  40. ^ Ямсиривонг, Опас (2016). Программирование с C. EDUCATION PUBLIC COMPANY LIMITED, стр. 225–230. Бангкок, Таиланд: SE -  978-616-08-2740-4 .
  41. ^ Раймонд, Эрик С. (11 октября 1996 г.). Словарь нового хакера (3-е изд.). МТИ Пресс. п. 432. ИСБН  978-0-262-68092-9 . Проверено 5 августа 2012 г.
  42. ^ «Страница руководства для lint (раздел 1 freebsd)» . unix.com . 24 мая 2001 года . Проверено 15 июля 2014 г.
  43. ^ «CS107 Valgrind Memcheck» . веб-сайт Stanford.edu . Проверено 23 июня 2023 г.
  44. ^ Гастингс, Рид; Джойс, Боб. «Очистка: быстрое обнаружение утечек памяти и ошибок доступа» (PDF) . Pure Software Inc .: 9.
  45. ^ Дейл, Нелл Б.; Уимс, Чип (2014). Программирование и решение проблем на C++ (6-е изд.). Берлингтон, Массачусетс: Jones & Bartlett Learning. ISBN  978-1449694289 . OCLC   894992484 .
  46. ^ «С — мать всех языков» . Академия ИКТ при ИИТК . 13 ноября 2018 года. Архивировано из оригинала 31 мая 2021 года . Проверено 11 октября 2022 г.
  47. ^ «1. Расширение Python с помощью C или C++» . Документация Python 3.10.7 . Архивировано из оригинала 5 ноября 2012 года . Проверено 11 октября 2022 г.
  48. ^ Конрад, Майкл (22 января 2018 г.). «Обзор движка Perl 5» . Opensource.com . Архивировано из оригинала 26 мая 2022 года . Проверено 11 октября 2022 г.
  49. ^ «На Ruby из C и C++» . Язык программирования Ruby . Архивировано из оригинала 12 августа 2013 года . Проверено 11 октября 2022 г.
  50. ^ Пара, Майкл (3 августа 2022 г.). «Что такое PHP? Как написать свою первую программу PHP» . freeCodeCamp . Архивировано из оригинала 4 августа 2022 года . Проверено 11 октября 2022 г.
  51. ^ Справочник доктора Добба . США: Miller Freeman, Inc., ноябрь – декабрь 1995 г.
  52. ^ «Использование C для программирования CGI» . linuxjournal.com. 1 марта 2005 года. Архивировано из оригинала 13 февраля 2010 года . Проверено 4 января 2010 г.
  53. ^ Перкинс, Люк (17 сентября 2013 г.). «Веб-разработка на C: безумие? Или безумие, как лиса?» . Середина . Архивировано из оригинала 4 октября 2014 года . Проверено 8 апреля 2022 г.
  54. ^ Муньос, Дэниел. «Спустя все эти годы, мир по-прежнему опирается на программирование на языке C» . Блог Toptal Engineering . Проверено 17 ноября 2023 г.
  55. ^ Мец, Кейд. «Деннис Ричи: Плечи, на которых стоял Стив Джобс» . Проводной . Архивировано из оригинала 12 апреля 2022 года . Проверено 19 апреля 2022 г.
  56. ^ corob-msft (31 марта 2022 г.). «Директивы Pragma и ключевые слова __pragma и _Pragma» . Microsoft Learn . Архивировано из оригинала 24 сентября 2022 года . Проверено 24 сентября 2022 г.
  57. ^ «Прагмы (препроцессор C)» . GCC, Коллекция компиляторов GNU . Архивировано из оригинала 17 июня 2002 года . Проверено 24 сентября 2022 г.
  58. ^ «Прагмы» . Руководство и справочник разработчика классического компилятора Intel C++ . Интел. Архивировано из оригинала 10 апреля 2022 года . Проверено 10 апреля 2022 г.
  59. ^ «Во славу препроцессора C» . апенварр . 13 августа 2007 года . Проверено 9 июля 2023 г.
  60. ^ Робертс, Эрик С. (21 марта 1989 г.). «Реализация исключений в C» (PDF) . Центр системных исследований DEC . СРЦ-РР-40. Архивировано (PDF) из оригинала 15 января 2017 г. Проверено 4 января 2022 г.
  61. ^ Макмиллан, Роберт (1 августа 2013 г.). «Ява теряет свое моджо?» . Проводной . Архивировано из оригинала 15 февраля 2017 года . Проверено 5 марта 2017 г.
  62. ^ О'Риган, Джерард (24 сентября 2015 г.). Основы вычислений: сборник избранных ключевых технологических компаний . Спрингер. ISBN  978-3319214641 . OCLC   922324121 .
  63. ^ Раухвергер, Лоуренс (2004). Языки и компиляторы для параллельных вычислений: 16-й международный семинар, LCPC 2003, Колледж-Стейшн, Техас, США, 2–4 октября 2003 г.: пересмотренные статьи . Спрингер. ISBN  978-3540246442 . OCLC   57965544 .
  64. ^ Страуструп, Бьярн (1993). «История C++: 1979–1991» (PDF) . Архивировано (PDF) из оригинала 2 февраля 2019 г. Проверено 9 июня 2011 г.

Источники [ править ]

Дальнейшее чтение [ править ]

Внешние ссылки [ править ]

Arc.Ask3.Ru: конец переведенного документа.
Arc.Ask3.Ru
Номер скриншота №: 6293e6773b9517362e186bae41219823__1718957760
URL1:https://arc.ask3.ru/arc/aa/62/23/6293e6773b9517362e186bae41219823.html
Заголовок, (Title) документа по адресу, URL1:
C (programming language) - Wikipedia
Данный printscreen веб страницы (снимок веб страницы, скриншот веб страницы), визуально-программная копия документа расположенного по адресу URL1 и сохраненная в файл, имеет: квалифицированную, усовершенствованную (подтверждены: метки времени, валидность сертификата), открепленную ЭЦП (приложена к данному файлу), что может быть использовано для подтверждения содержания и факта существования документа в этот момент времени. Права на данный скриншот принадлежат администрации Ask3.ru, использование в качестве доказательства только с письменного разрешения правообладателя скриншота. Администрация Ask3.ru не несет ответственности за информацию размещенную на данном скриншоте. Права на прочие зарегистрированные элементы любого права, изображенные на снимках принадлежат их владельцам. Качество перевода предоставляется как есть. Любые претензии, иски не могут быть предъявлены. Если вы не согласны с любым пунктом перечисленным выше, вы не можете использовать данный сайт и информация размещенную на нем (сайте/странице), немедленно покиньте данный сайт. В случае нарушения любого пункта перечисленного выше, штраф 55! (Пятьдесят пять факториал, Денежную единицу (имеющую самостоятельную стоимость) можете выбрать самостоятельно, выплаичвается товарами в течение 7 дней с момента нарушения.)