directory search
Algorithms Algorithms(算法) bsearch bsearch_s qsort qsort_s Atomic operations Atomic operations library(原子操作库) ATOMIC_*_LOCK_FREE atomic_compare_exchange_strong atomic_compare_exchange_strong_explicit atomic_compare_exchange_weak atomic_compare_exchange_weak_explicit atomic_exchange atomic_exchange_explicit atomic_fetch_add atomic_fetch_add_explicit atomic_fetch_and atomic_fetch_and_explicit atomic_fetch_or atomic_fetch_or_explicit atomic_fetch_sub atomic_fetch_sub_explicit atomic_fetch_xor atomic_fetch_xor_explicit atomic_flag atomic_flag_clear atomic_flag_clear_explicit ATOMIC_FLAG_INIT atomic_flag_test_and_set atomic_flag_test_and_set_explicit atomic_init atomic_is_lock_free atomic_load atomic_load_explicit atomic_signal_fence atomic_store atomic_store_explicit atomic_thread_fence(线程围栏) ATOMIC_VAR_INIT kill_dependency memory_order(内存排序) C keywords auto(自动存储) break(跳出循环) C keywords(关键词) case char const(常量修饰符) continue default(预设运算式) do double(双精度浮点型) else enum(枚举类型) extern(全局变量) float(浮点数) for fortran goto(goto语句) if(if语句) inline(行内函式) int long(长整型) register(寄存器变量) restrict( restrict类型限定符) return short signed sizeof(sizeof运算符) static(静态变量) struct(结构体) switch(switch语句) typedef(typedef关键字) union(联合体) unsigned(无符号) void(空类型) volatile(volatile变量) while(while语句) _Alignas _Alignof _Atomic _Bool _Complex _Generic _Imaginary _Noreturn _Static_assert _Thread_local C language #define directive #elif directive #else directive #endif directive #error directive #if directive #ifdef directive #ifndef directive #include directive #line directive #pragma directive alignas(对齐指定符) Alternative operators and tokens(替代运算符和令牌) Analyzability Arithmetic operators Arithmetic types Array declaration(数组声明) Array initialization(阵列初始化) ASCII Chart Assignment operators(赋值运算符) types(atomic类型限定符) Basic concepts Bit fields(位域) break statement C language C Operator Precedence cast operator character constant(字符字面量) Comments(注释符) Comparison operators(比较运算符) compound literals(符合字面量) Conditional inclusion(条件包含) Conformance(一致性) const type qualifier(const 限定符) Constant expressions(常量表达) continue statement Declarations(声明) do-while loop Enumerations(枚举类型) Escape sequences(转义字符) Expressions(表达式) External and tentative definitions(外部和暂定的定义) File scope(文件范围) floating constant(浮点常量) for loop Function declarations(函数声明) Function definitions(函数声明) Functions Generic selection泛型选择 goto statement Identifier(标示符) if statement Implicit conversions(隐式转换) Increment/decrement operators(前置/后置操作符) Initialization(初始化) inline function specifier(内联函式) integer constant Lifetime(生命期) Logical operators(逻辑运算符) Lookup and name spaces Main function(主函式) Member access operators(会员接入运营商) Memory model Objects and alignment(字节对齐) Order of evaluation(评估顺序) Other operators Phases of translation(翻译阶段) Pointer declaration Preprocessor(预处理) restrict type qualifier(restrict类型限定符) return statement Scalar initialization(标量类型初始化) Scope(范围) sizeof operator(sizeof运算符) Statements(陈述) static assert declaration(静态断言声明) Static storage duration(静态存储周期) Storage-class specifiers(存储类说明符) string literals(字符串字面量) Struct and union initialization(结构体与联合体初始化) Struct declaration(结构体声明) switch statement Thread storage duration(线程存储时间) Type Type(类型) Typedef declaration(Typedef声明) Undefined behavior(未定义行为) Union declaration(联合体声明) Value categories(值类别) Variadic arguments(变长参数宏) volatile type qualifier(volatile 类型限定符) while loop _Alignof operator _Noreturn function specifier Date and time asctime(asctime函数) asctime_s clock CLOCKS_PER_SEC clock_t ctime(ctime函数) ctime_s Date and time utilities(日期和时间库) difftime(计算两个时间的间隔) gmtime gmtime_s localtime localtime_s mktime(将时间结构数据转换成经过的秒数的函数) strftime(格式化输出时间函数) time timespec timespec_get time_t tm wcsftime(格式化时间宽字符) Dynamic memory management aligned_alloc C memory management library(内存管理库) calloc free(释放动态分配空间的函数) malloc(动态分配内存空间的函数) realloc(重新分配内存空间的函数) Error handling abort_handler_s assert(断言) constraint_handler_t errno(错误报告) Error handling(错误处理) Error numbers(错误个数) ignore_handler_s set_constraint_handler_s static_assert File input/output clearerr(清除/复位) fclose feof ferror fflush(清空文件缓冲区) fgetc fgetpos fgets fgetwc fgetws File input/output fopen fopen_s fprintf fprintf_s fputc fputs fputwc fputws fread freopen freopen_s fscanf fscanf_s fseek fsetpos ftell fwide fwprintf fwprintf_s fwrite fwscanf fwscanf_s getc getchar gets gets_s getwchar perror printf printf_s putc putchar puts putwc putwchar remove rename rewind scanf scanf_s setbuf setvbuf snprintf sprintf sscanf sscanf_s swprintf swprintf_s swscanf swscanf_s tmpfile tmpfile_s tmpnam tmpnam_s ungetc ungetwc vfprintf vfprintf_s vfscanf vfscanf_s vfwprintf vfwprintf_s vfwscanf vfwscanf_s vprintf vprintf_s vscanf vscanf_s vsnprintf vsprintf vsscanf vsscanf_s vswprintf vswprintf_s vswscanf vswscanf_s vwprintf vwprintf_s vwscanf vwscanf_s wprintf wprintf_s wscanf wscanf_s Localization support lconv LC_ALL LC_COLLATE LC_CTYPE LC_MONETARY LC_NUMERIC LC_TIME localeconv Localization support setlocale Numerics abs acos acosf acosh acoshf acoshl acosl asin asinf asinh asinhf asinhl asinl atan atan2 atan2f atan2l atanf atanh atanhf atanhl atanl cabs cabsf cabsl cacos cacosf cacosh cacoshf cacoshl cacosl carg cargf cargl casin casinf casinh casinhf casinhl casinl catan catanf catanh catanhf catanhl catanl cbrt cbrtf cbrtl ccos ccosf ccosh ccoshf ccoshl ccosl ceil ceilf ceill cexp cexpf cexpl cimag cimagf cimagl clog clogf clogl CMPLX CMPLXF CMPLXL Common mathematical functions complex Complex number arithmetic conj conjf conjl copysign copysignf copysignl cos cosf cosh coshf coshl cosl cpow cpowf cpowl cproj cprojf cprojl creal crealf creall csin csinf csinh csinhf csinhl csinl csqrt csqrtf csqrtl ctan ctanf ctanh ctanhf ctanhl ctanl div double_t erf erfc erfcf erfcl erff erfl exp exp2 exp2f exp2l expf expl expm1 expm1f expm1l fabs fabsf fabsl fdim feclearexcept fegetenv fegetexceptflag fegetround feholdexcept feraiseexcept fesetenv fesetexceptflag fesetround fetestexcept feupdateenv FE_ALL_EXCEPT FE_DFL_ENV FE_DIVBYZERO FE_DOWNWARD FE_INEXACT FE_INVALID FE_OVERFLOW FE_TONEAREST FE_TOWARDZERO FE_UNDERFLOW FE_UPWARD Floating-point environment float_t floor floorf floorl fma fmaf fmal fmax fmaxf fmaxl fmin fminf fminl fmod fmodf fmodl fpclassify FP_INFINITE FP_NAN FP_NORMAL FP_SUBNORMAL FP_ZERO frexp frexpf frexpl HUGE_VAL HUGE_VALF HUGE_VALL hypot hypotf hypotl I ilogb ilogbf ilogbl imaginary imaxabs imaxdiv INFINITY isfinite isgreater isgreaterequal isinf isless islessequal islessgreater isnan isnormal isunordered labs ldexp ldexpf ldexpl ldiv lgamma lgammaf lgammal llabs lldiv llrint llrintf llrintl llround llroundf llroundl log log10 log10f log10l log1p log1pf log1pl log2 log2f log2l logb logbf logbl logf logl lrint lrintf lrintl lround lroundf lroundl MATH_ERREXCEPT math_errhandling MATH_ERRNO modf modff modfl nan NAN nanf nanl nearbyint nearbyintf nearbyintl nextafter nextafterf nextafterl nexttoward nexttowardf nexttowardl Numerics pow powf powl Pseudo-random number generation rand RAND_MAX remainder remainderf remainderl remquo remquof remquol rint rintf rintl round roundf roundl scalbln scalblnf scalblnl scalbn scalbnf scalbnl signbit sin sinf sinh sinhf sinhl sinl sqrt sqrtf sqrtl srand tan tanf tanh tanhf tanhl tanl tgamma tgammaf tgammal trunc truncf truncl Type-generic math _Complex_I _Imaginary_I Program support abort atexit at_quick_exit exit EXIT_FAILURE EXIT_SUCCESS getenv getenv_s jmp_buf longjmp Program support utilities quick_exit raise setjmp SIGABRT SIGFPE SIGILL SIGINT signal SIGSEGV SIGTERM sig_atomic_t SIG_DFL SIG_ERR SIG_IGN system _Exit Strings atof atoi atol atoll btowc c16rtomb c32rtomb char16_t char32_t isalnum isalpha isblank iscntrl isdigit isgraph islower isprint ispunct isspace isupper iswalnum iswalpha iswblank iswcntrl iswctype iswdigit iswgraph iswlower iswprint iswpunct iswspace iswupper iswxdigit isxdigit mblen mbrlen mbrtoc16 mbrtoc32 mbrtowc mbsinit mbsrtowcs mbsrtowcs_s mbstate_t mbstowcs mbstowcs_s mbtowc memchr memcmp memcpy memcpy_s memmove memmove_s memset memset_s Null-terminated byte strings Null-terminated multibyte strings Null-terminated wide strings strcat strcat_s strchr strcmp strcoll strcpy strcpy_s strcspn strerror strerrorlen_s strerror_s Strings library strlen strncat Thread support call_once cnd_broadcast cnd_destroy cnd_init cnd_signal cnd_timedwait cnd_wait mtx_destroy mtx_init mtx_lock mtx_plain mtx_recursive mtx_timed mtx_timedlock mtx_trylock mtx_unlock once_flag ONCE_FLAG_INIT thrd_busy thrd_create thrd_current thrd_detach thrd_equal thrd_error thrd_exit thrd_join thrd_nomem thrd_sleep thrd_success thrd_timedout thrd_yield Thread support library thread_local tss_create tss_delete TSS_DTOR_ITERATIONS tss_get tss_set Type support Boolean type support library Fixed width integer types FLT_EVAL_METHOD FLT_ROUNDS max_align_t NULL Numeric limits offsetof ptrdiff_t size_t Type support Variadic functions Variadic functions va_arg va_copy va_end va_list va_start
characters

当预期在不同类型的值的上下文中使用表达式时,可能会发生转换

int n = 1L; // expression 1L has type long, int is expectedn = 2.1; // expression 2.1 has type double, int is expectedchar *p = malloc(10); // expression malloc(10) has type void*, char* is expected

转换发生在以下情况:

按照分配进行转换

  • 在赋值运算符中,右侧操作数的值被转换为左侧操作数的非限定类型。

  • 在标量初始化中,初始化表达式的值被转换为被初始化的对象的非限定类型

  • 在函数调用表达式中,对于具有原型的函数,将每个参数表达式的值转换为相应参数的非限定声明类型

  • 在return语句中,操作数的值return被转换为具有函数返回类型的对象

请注意,除转换外,实际分配也会从浮点类型中移除额外的范围和精度,并禁止重叠; 这些特性不适用于转换,就像通过分配一样。

默认参数优化

在调用时的函数调用表达式中。

1)没有原型的功能

2)可变参数函数,其中参数表达式是与省略号参数匹配的尾随参数之一

整数类型的每个参数都经过整数提升(参见下文),并且每个类型的参数都float被隐式转换为类型double

int add_nums(int count, ...);int sum = add_nums(2, 'c', true); // add_nums is called with three ints: (2, 99, 1)

请注意,float complexfloat imaginary没有提升到double complexdouble imaginary在这种情况下。

通常的算术转换

以下算术运算符的参数经过隐式转换,以获得公共实数类型,这是执行计算的类型:

  • 二进制算术*,/,%,+, -

  • 关系运算符<,>,<=,> =,==,!=

  • 二进制按位运算&,^,|,

  • 条件操作符?:

1)如果一个操作数是long doublelong double complexlong double imaginary,另一个操作数被隐式转换如下:

  • 整数或实际浮动类型 long double

  • 复杂类型 long double complex

  • 虚构类型 long double imaginary

2)否则,如果一个操作数是doubledouble complexdouble imaginary,另一个操作数被隐式转换如下:

  • 整数或实际浮动类型 double

  • 复杂类型 double complex

  • 虚构类型 double imaginary

3)否则,如果一个操作数是floatfloat complexfloat imaginary,另一个操作数被隐式转换如下:

  • 整数类型为float(唯一可能的实际类型是float,保持原样)

  • 复杂类型依然存在 float complex

  • 虚构类型仍然存在 float imaginary

4)否则,两个操作数都是整数。在这种情况下,首先,两个操作数都进行整数升级(见下文)。然后

  • 如果促销后的类型相同,则该类型是常见类型

  • 否则,如果促销后的两个操作数具有相同的签名(均为有符号或无符号),则具有较低转换等级的操作数(请参见下文)会隐式转换为具有较高转换等级的操作数的类型

  • 否则,签名会有所不同:如果具有无符号类型的操作数的转换等级大于或等于有符号操作数类型的等级,则带符号类型的操作数将隐式转换为无符号类型

  • 否则,签名是不同的,并且带符号的操作数的等级大于无符号的操作数的等级。在这种情况下,如果有符号类型可以表示所有无符号类型的值,那么具有无符号类型的操作数将隐式转换为有符号操作数的类型。

  • 否则,两个操作数都会隐式转换为带符号操作数类型的无符号类型。

1.f + 20000001; // int is converted to float, giving 20000000.00                // addition and then rounding to float gives 20000000.00(char)'a' + 1L; // First, char is promoted back to int.                // this is signed + signed case, different rank                // int is converted to long, the result is 98 signed long2u - 10; // signed / unsigned, same rank         // 10 is converted to unsigned, unsigned math is modulo UINT_MAX+1         // assuming 32 bit ints, result is 4294967288 of type unsigned int (aka UINT_MAX-7)0UL - 1LL; // signed/unsigned diff rank, rank of signed is greater.           // If sizeof(long) == sizeof(long long), signed cannot represent all unsigned           // this is the last case: both operands are converted to unsigned long long           // the result is 18446744073709551615 (ULLONG_MAX) of type unsigned long long

结果类型确定如下:

  • 如果两个操作数都很复杂,则结果类型很复杂

  • 如果两个操作数都是虚构的,则结果类型是虚构的

  • 如果两个操作数都是实数,则结果类型是实数

  • 如果两个浮点操作数具有不同的类型域(复数与实数,复数与虚数,或虚数与实数),则结果类型很复杂

double complex z = 1 + 2*I;double f = 3.0;z + f; // z remains as-is, f is converted to double, the result is double complex

与往常一样,浮点运算符的结果可能比其类型所指示的范围和精度更高(请参阅参考资料FLT_EVAL_METHOD)。

注意:实数和虚数操作数不会隐式转换为复数,因为这样做需要额外的计算,而在涉及无穷大,NaN和带符号的零的某些情况下会产生不希望的结果。例如,如果将实数转换为复数,则2.0×(3.0 +i∞)将评估为(2.0 + i0.0)×(3.0 +i∞)⇒(2.0×3.0-0.0×∞)+ i(2.0× ∞+ 0.0×3.0)⇒NaN +i∞而不是正确的6.0 +i∞。如果虚数转换为复数,则i2.0×(∞+ i3.0)将评估为(0.0 + i2.0)×(∞+ i3.0)⇒(0.0×∞ -  2.0×3.0)+ i(0.0 ×3.0 + 2.0×∞)⇒NaN +i∞而不是-6.0 +i∞。

注意:无论通常的算术转换如何,在as-if规则下,通过这些规则,计算总是可以以窄于指定符的类型执行。

价值转化

左值转换

任何非数组类型的任何左值表达式,当在除。以外的任何上下文中使用时。

  • 作为操作符的操作数(如果允许)

  • 作为前/后增量和减量运算符的操作数。

  • 作为成员访问(点)运算符的左侧操作数。

  • 作为赋值和复合赋值操作符的左侧操作数。

  • 作为 sizeof 的操作数

进行左值转换:类型保持不变,但会丢失 const / volatile / restrict-qualifiers 和原子属性(如果有的话)。价值保持不变,但失去了左值属性(地址可能不再被采用)。

如果左值具有不完整类型,则行为未定义。

如果左值指定一个自动存储持续时间的对象,其地址从未被采用,并且该对象未初始化(未使用初始化器声明并且在使用之前未对其进行分配),则行为是未定义的。

此转换将模拟对象的值从其位置的内存负载。

volatile int n = 1;int x = n;            // lvalue conversion on n reads the value of nvolatile int* p = &n; // no lvalue conversion: does not read the value of n

数组到指针的转换

数组类型的任何左值表达式,当在除。以外的任何上下文中使用时。

  • 作为操作符地址的操作数

  • 作为 sizeof 的操作数

  • 作为用于数组初始化的字符串文字

经历转换到非左值指针到它的第一个元素。

如果数组被声明为注册,则行为是未定义的。

int a[3], b[3][4];int* p = a;      // conversion to &a[0]int (*q)[4] = b; // conversion to &b[0]

函数指针转换

任何函数指示符表达式,当在除。以外的任何上下文中使用时。

  • 作为操作符地址的操作数

  • 作为sizeof的操作数

经过转换到非左值指针指向由表达式指定的函数。

int f(int);int (*p)(int) = f; // conversion to &f(***p)(1); // repeated dereference to f and conversion back to &f

隐式转换语义

隐式转换,无论是通过赋值还是通常的算术转换,都由两个阶段组成:

1)价值转化(如果适用)

2)下面列出的转换之一(如果它可以产生目标类型)

兼容的类型

将任何类型的值转换为任何兼容类型始终是不可操作的,并且不会更改表示形式。

uint8_t (*a)[10];         // if uint8_t is a typedef to unsigned charunsigned char (*b)[] = a; // then these pointer types are compatible

整数升级

整数推广是任意整数类型的值的隐式转换与秩小于或等于秩为int或类型_Bool,整型,符号int,unsigned int类型的位域的,以类型的值intunsigned int

如果int可以表示原始类型的整个值范围(或原始位域的值的范围),则将该值转换为类型int。否则,该值将转换为unsigned int

整数升级保持价值,包括符号:

int main(void) {   void f(); // old-style function declaration
   char x = 'a'; // integer conversion from int to char   f(x); // integer promotion from char back to int}void f(x) int x; {} // the function expects int

上面的 rank 是每个整数类型的属性,定义如下:

1)所有有符号整数类型的行列是不同的,并且随着它们的精度而增加:被签名的char的等级<短的等级<int的等级<long int的等级<long long 的等级 int

2)所有有符号整数类型的等级等于对应无符号整数类型的等级

3)任何标准整数类型的等级大于任何相同大小的扩展整数类型的等级(即,__int64 <等级长long int,但 long long 等级<由于规则而等于__int128等级(1))

4)char 的等级等于 signed char 的等级和 unsigned char 的等级

5)_Bool 的排名小于任何其他标准整数类型的排名

6)任何枚举类型的等级等于其兼容整数类型的等级

7)排名是传递性的:如果T1的等级<T2的等级和T2的等级<T3的等级,那么T1的等级<T3的等级

8)上面未涉及的扩展整数类型的相对排序的任何方面都是实现定义的

注意:整数升级只适用。

  • 作为通常算术转换的一部分(见上文)

  • 作为默认参数促销的一部分(参见上文)

  • 到一元算术运算符的操作数+和 -

  • 到一元位运算符〜的操作数

  • 移位运算符<<和>>的两个操作数

布尔转换

任何标量类型的值都可以隐式转换为_Bool。将等于零的值转换为0,将其他所有值转换为1

bool b1 = 0.5;              // b1 == 1 (0.5 converted to int would be zero)bool b2 = 2.0*_Imaginary_I; // b2 == 1 (but converted to int would be zero)bool b3 = 0.0 + 3.0*I;      // b3 == 1 (but converted to int would be zero)bool b4 = 0.0/0.0;          // b4 == 1 (NaN does not compare equal to zero)

整数转换

任何整数类型的值都可以隐式转换为任何其他整数类型。除了上述促销和布尔转换所涵盖的地方外,规则如下:

  • 如果目标类型可以表示源类型的整个值范围,则值不变

  • 否则,如果目标类型是无符号的,则将值2 b(其中b是目标类型中的位数)重复减去或添加到源值直到结果符合目标类型。换句话说,无符号整数实现模运算。

  • 否则,如果目标类型被签名,则行为是实现定义的(可能包括提升信号)

char x = 'a'; // int -> char, result unchangedunsigned char n = -123456; // target is unsigned, result is 192 (that is, -123456+483*256)signed char m = 123456;    // target is signed, result is implementation-defined

Real floating-integer conversions

任何实数浮点类型的有限值都可以隐式转换为任何整数类型。除了上述布尔转换覆盖的地方,规则是:

  • 小数部分被丢弃(截至零)。

    • 如果结果值可以用目标类型表示,则使用该值

    • 否则,行为是不确定的

int n = 3.14; // n == 3int x = 1e10; // undefined behavior for 32-bit int

任何整数类型的值都可以隐式转换为任何实数浮点类型。

  • 如果该值可以完全由目标类型表示,则该值不变

  • 如果值可以表示,但不能精确表示,则结果是最接近的较高值或最接近的较低值(换句话说,舍入方向是实现定义的),但是如果支持IEEE算术,舍入是最接近的。FE_INEXACT在这种情况下是否提出是没有具体说明的。

  • 如果该值不能表示,行为是未定义的,但如果支持IEEE算术,FE_INVALID则引发并且结果值未指定。

这种转换的结果可能比其目标类型指示的范围和精度更高(请参阅FLT_EVAL_METHOD

如果FE_INEXACT在浮点到整数转换中需要控制,rintnearbyint可以使用。

double d = 10; // d = 10.00float f = 20000001; // f = 20000000.00 (FE_INEXACT)float x = 1+(long long)FLT_MAX; // undefined behavior

实际浮点转换

任何实际浮动类型的值都可以隐式转换为任何其他实际浮动类型。

  • 如果该值可以完全由目标类型表示,则不会改变

  • 如果值可以表示,但不能精确表示,则结果是最接近的较高值或最接近的较低值(换句话说,舍入方向是实现定义的),但是如果支持IEEE算术,舍入是最接近的

  • 如果该值无法表示,则行为未定义

这种转换的结果可能比其目标类型指示的范围和精度更高(请参阅FLT_EVAL_METHOD

double d = 0.1; // d = 0.1000000000000000055511151231257827021181583404541015625float f = d;    // f = 0.100000001490116119384765625float x = 2*(double)FLT_MAX; // undefined

复杂的类型转换

任何复杂类型的值都可以隐式转换为任何其他复杂类型。实部和虚部分别遵循实际浮动类型的转换规则。

double complex d = 0.1 + 0.1*I;float complex f = d; // f is (0.100000001490116119384765625, 0.100000001490116119384765625)

虚构类型转换

任何虚构类型的值都可以隐式转换为任何其他虚构类型。虚部遵循实际浮动类型的转换规则。

double imaginary d = 0.1*_Imaginary_I;float imaginary f = d; // f is 0.100000001490116119384765625*I

真正复杂的转换

任何实际浮动类型的值都可以隐式转换为任何复杂类型。

  • 结果的实际部分取决于实际浮动类型的转换规则

  • 结果的虚部为正零(或非IEEE系统上的无符号零)

任何复杂类型的值都可以隐式转换为任何实际浮动类型。

  • 实部按照真实浮动类型的规则进行转换

  • 虚部被丢弃

注意:在复数到实数转换中,虚数部分的 NaN 不会传播到实际结果。

实际的虚拟转换

任何虚数类型的值都可以隐式转换为任何实数类型(整型或浮点型)。除目标类型为_Bool 之外,结果始终为正值(或无符号)零,在这种情况下,布尔转换规则适用。

任何实数类型的值都可以隐式转换为任何虚数类型。结果总是一个正的虚构的零。

复数 - 虚数转换

任何虚构类型的值都可以隐式转换为任何复杂类型。

  • 结果的实际部分是正的零

  • 结果的虚数部分遵循相应实际类型的转换规则

任何复杂类型的值都可以隐式转换为任何虚构类型。

  • 真正的部分被丢弃

  • 结果的虚数部分遵循相应实际类型的转换规则

double imaginary z = I * (3*I); // the complex result -3.0+0i loses real part, gives zero

指针转换

一个指针void可以使用以下语义隐式转换为指向对象类型的指针:

  • 如果指向对象的指针转换为指向 void 和指向的指针,则其值将与原始指针相等。

  • 没有其他担保提供

int* p = malloc(10 * sizeof(int)); // malloc returns void*

指向非限定类型的指针可以隐式转换为指向该类型限定版本的指针(换句话说,可以添加 const,volatile和 restrict 限定符。原始指针和结果比较相等。

int n;const int* p = &n; // &n has type int*

任何具有值的整数常量表达式0以及将值void*转换为0的整型指针表达式都可以隐式转换为任何指针类型(既指向对象又指向函数的指针)。结果是它的类型的空指针值,保证比较不等于该类型的任何非空指针值。这个整数或 void *表达式被称为空指针常量,标准库提供这个常量的一个定义作为宏NULL

int* p = 0;double* q = NULL;

笔记

尽管任何算术运算符中的有符号整数溢出都是未定义行为,但在整数转换中溢出有符号整数类型仅仅是未指定的行为。

另一方面,尽管任何算术运算符(和整数转换)中的无符号整数溢出是一个定义明确的操作,并遵循模算术规则,但浮点到整数转换中的无符号整数溢出是未定义的行为:可以转换为无符号整数的实际浮动类型的值是来自打开间隔(-1; Unnn_MAX + 1)的值。

unsigned int n = -1.0; // undefined behavior

指针和整数之间的转换(除了指向_Bool 的指针和整数常量表达式,值为零到指针)之间,指向对象的指针(除非指向 void 的指针或指向 void 的指针之外)以及指向函数的指针之间的转换函数具有兼容类型)从不隐含,并且需要一个演员操作符。

在指向函数的指针和指向对象的指针(包括 void *)或整数之间没有转换(隐式或显式)。

参考

  • C11 standard (ISO/IEC 9899:2011):

    • 6.3 Conversions (p: 50-56)

  • C99 standard (ISO/IEC 9899:1999):

    • 6.3 Conversions (p: 42-48)

  • C89/C90 standard (ISO/IEC 9899:1990):

    • 3.2 Conversions

Previous article: Next article: