当前位置:软件学习 > 其它软件 >>

C99标准详解

变量类型
在C89里新加了一些变量类型:
void
void*
signed char
unsigned char
unsigned short
unsigned long
long double

以及已有类型的新名称:
signed short表示short
signed int表示int
signed long表示long

C9X也加入了新的变量类型:
_Bool
long long
unsigned long long
float _Imaginary
float _Complex
double _Imaginary
double _Complex
long dobule _Imaginary
long double _Complex


C9X也允许扩展的整型类型,它们定义在<inttypes.h>和<stdint.h>里,比如int64_t、uint32_t等等。还有定义在<stdbool.h>里的布尔类型bool,它作如下定义:
#define bool    _Bool
#define true    1
#define false   0
bool虽然看上去像int,但还是有稍许不同。比如:
    bool b = 0.5;
    int n = 0.5;
    printf ("b: %d, n: %d\n", b, n);

结果为b: 1, n: 0

 整型与浮点型类型汇总(linux3.0.0-17-generic x86)
 

类型 sizeof 格式化字符串 常量举例
char 1 %hhd 123
unsigned char 1 %hhu 234U
short 2 %hd 12345
unsigned short 2 %hu 12345U
int 4 %d 1234567898
unsigned int 4 %u 1234567898U
long 4 %ld 1234567898L
unsigned long 4 %lu 1234567898UL
long long 8 %lld 12345678987654321LL
unsigned long long 8 %llu 12345678987654321ULL
float 4 %f 1234.5678F
double 8 %lf 123456789.987654
long double 12 %Lf 12345678912345.987654321L
 

 一些浮点数的操作可能会导致非正常的值,例如:
-1的根号值为NaN。(Not a Number)
1除以0和log(0)的结果都是无穷大。
C99在<math.h>里定义了fpclassify来提供对浮点数的类别判断,它是一个宏:
Macro: int fpclassify (float-type x),返回值为以下的某值:
FP_NAN:浮点数x不是一个数。
FP_INFINITE:x的值为正负无穷大。
FP_ZERO:x的值为正负0。
FP_SUBNORMAL:x的绝对值过小,以至于无法以正常的形式表示,所以用更低精度、但离0更接近的形式表示。
FP_NORMAL:x为除以上情况之外的正常的值。
除了fpclassify,还有另外几个类似的宏:
Macro: int isfinite (float-type x):等价于(fpclassify (x) != FP_NAN && fpclassify (x) != FP_INFINITE)
Macro: int isnormal (float-type x):等价于(fpclassify (x) == FP_NORMAL)
Macro: int isnan (float-type x):等价于(fpclassify (x) == FP_NAN)
Ubuntu使用fpclassify时可能会出现错误:
undefined reference to `__fpclassify'
这是一个已知的bug,更新gtk-gnutella包可以解决。当然,你还要确保gcc使用了-lm选项来引入math库。
 
复数类型:
使用<complex.h>里的_Complex类型,或它的别名complex可以操作复数。它的用法为:
complex c = 35 + 78i; //与35 + I*78等价
complex a = c * 2;
printf("%f+%fi", creal(c), cimag(c));
printf("%f+%fi", creal(a), cimag(a));

其中creal和cimag分别得到复数的实数和虚数部分。
_Imagianry表示一个虚数,gcc没有支持这个关键字。
类型 sizeof 常量举例
float complex 8 12.3f+I*45.6f
double complex 16 1.23+4.56i
long double complex 24 1.23l+4.56l
complex等价于double complex。
 

结构体
里的所有对象都必须表示成连续的字节序列,且每个都至少有8位的宽度。在一个36位字长的机器上,一个字节可以定义成9、12、18、或36位,对于占用一个字节的字符类型来说,它的位数也不会小于8。sizeof返回的“字节”数也是与机器无关的,它可能是8位、9位或其它的位数。
因为这种宽度限制,所以空结构体的对象也要占用至少一字节的空间。比如:
struct Empty
{
};
printf("%d, ", sizeof(struct Empty));
struct Empty e1, e2;
printf("%p, %p\n", &e1, &e2);
输出为:0, 0xbf9ccf8e, 0xbf9ccf8f

再讨论下包含空结构体对象的结构体:
struct EmptyGroup
{
    struct Empty e1;
    struct Empty e2;
    struct Empty e3;
};

int main()
{
    struct EmptyGroup eg1, eg2;
    printf("%p, %p\n", &eg1, &eg2);
    printf("%p, %p, %p\n", &(eg1.e1), &(eg1.e2), &(eg1.e3));
    return 0;
}
输出为:
0xbff7965e, 0xbff7965f
0xbff7965e, 0xbff7965e, 0xbff7965e
可以看到各成员共用一个地址。
注意,如果是C++,它的输出会有不同:
0xbfca68d8, 0xbfca68db
0xbfca68d8, 0xbfca68d9, 0xbfca68da
每个成员对象都占用了一个字节,这种特性在C++中保证了多重继承的可能性。

结构体的内存布局有一些限制:
1、结构体开头不能有空洞(hole);
2、成员会增加存储空间;
3、在结构体末,需要的时候可能会放置一个空洞来使结构体足够大,以便在数组里紧密排列并有恰当的内存对齐。

可变长度的结构体
在C89,有一种称为“struct hack”的方法来得到可变数组。
struct s
{
    int n_items;
    int items[1];
};
struct s *p = malloc(sizeof(struct s) + (n - 1) * sizeof(int));
这种方式可以使得结构体里的数组长度为n。但它被认为多少有些易做图的。C99提供了类似的但合法的“struct”机制:
struct OK
{
    int n;
    int a[];
};
struct OK *p = (struct OK *)malloc(sizeof(struct OK) + 10 * sizeof(int));
p->a[9] = 9;
注意只有结构体内最后的数组才可以有可变长度,且它不能是唯一的成员。

结构体的初始化与赋值
C89的扩展和C++都支持“Compound Literal”的概念。例如:
struct R
{
    int c;
    double d;
};

struct S
{
    int a;
    float b;
    struct R r;
    char *s;
};
结构体的初始化和赋值可以很简明:
    struct S s = { 1, 3.4, {6, 7.8}, "hello" };
    s = (struct S){ 1, 3.4, {6, 7.8}, "hello" };
    s.r = (struct R){6, 7.8};
C99提供了“Designated Initializers”的机制,它可以以任意顺序为结构体赋值:
    s.r = (struct R) { .c = 8, .d = 9.0 };
或 s.r = (struct R) { .d = 8.0, .c = 9 };

对于union,只能用Designated Initializers,比如:
u = { .a = 4 };
虽然Compound Literal也可以使用,但它的效果仅等同于cast,结果可能会不正确。

数组
C9X的可变长度数组是码农的福音。
    int n;
    scanf("%d", &n);
    int a[n];
    printf("%d", sizeof(a)/sizeof(a[0]));
由于它的存在,alloca这种东西就out了。使用alloca会得到编译警告。
如果说数组的Compound Literal带来很多便利的话:
int a[

补充:软件开发 , 其他 ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,