while (p = next(q)) {
/* ... */
}
void f(int i)
{
if (i< 0 || max<=i) error("Ошибка диапазона");
{
int a[max];
/* ... */
}
}
В языке С++ неинициализированное объявление считается определением; в языке С оно считается простым объявлением, поэтому его можно дублировать.
int x;
int x; /* определяет или объявляет одну целочисленную переменную
с именем x в программе на языке C; ошибка в языке C++ */
int
с одинаковыми именами находятся в разных модулях компиляции.
/* в файле x.c: */
int x;
/* в файле y.c: */
int x;
Ни компилятор языка С, ни компилятор языка С++ не найдет никаких ошибок в файлах x.c
или y.c
. Но если файлы x.c
и y.c
скомпилировать как файлы на языке С++, то редактор связей выдаст сообщение об ошибке, связанной с двойным определением. Если же файлы x.c
и y.c
скомпилировать на языке C, то редактор связей не выдаст сообщений об ошибке и (в полном соответствии с правилами языка C) будет считать, что речь идет об одной и той же переменной x
, совместно используемой в файлах x.c
и y.c
. Если хотите, чтобы в программе всеми модулями совместно использовалась одна глобальная переменная x
, то сделайте это явно, как показано ниже.
/* в файле x.c: */
int x = 0; /* определение */
/* в файле y.c: */
extern int x; /* объявление, но не определение */
Впрочем, лучше используйте заголовочный файл.
/* в файле x.h: */
extern int x; /* объявление, но не определение */
/* в файле x.c: */
#include "x.h"
int x = 0; /* определение */
/* в файле y.c: */
#include "x.h"
/* объявление переменной x находится в заголовочном файле */
А еще лучше: избегайте глобальных переменных.
27.3.4. Приведение типов в стиле языка С
В языке C (и в языке C++) можете явно привести переменную v
к типу T
, используя минимальные обозначения.
(T)v
v
получилась переменная типа T
). С другой стороны, этот стиль яростно отвергают программисты, занимающиеся сопровождением программ, поскольку такие преобразования остаются практически незаметными и никак не привлекают к себе внимания. Приведения в языке С++ (
int* p = (int*)7; /* интерпретирует битовую комбинацию:
reinterpret_cast
int x = (int)7.5; /* усекает переменную типа: static_cast
typedef struct S1 { /* ... */ } S1;
typedef struct S2 { /* ... */ } S2;
S1 a;
const S2 b; /* в языке С допускаются неинициализированные
/* константы */
S1* p = (S2*)&a /* интерпретирует битовую комбинацию:
reinterpret_cast
S2* q = (S2*)&b /* отбрасывает спецификатор const:
const_cast
S1* r = (S1*)&b /* удаляет спецификатор const и изменяет тип;
похоже на ошибку */
Мы не рекомендуем использовать макросы даже в программах на языке C (раздел 27.8), но, возможно, описанные выше идеи можно было бы выразить следующим образом:
#define REINTERPRET_CAST(T,v) ((T)(v))
#define CONST_CAST(T,v) ((T)(v))
S1* p = REINTERPRET_CAST (S1*,&a);
S2* q = CONST_CAST(S2*,&b);
Это не обеспечит проверку типов при выполнении операторов reinterpret_cast
и const_cast
, но сделает эти ужасные операции заметными и привлечет внимание программиста.