C 由实现定义的行为、未定义的行为与未明确的行为

Implementation-defined behavior

由实现定义的行为。例如,int 数据类型的内存空间大小为一般为 4 bytes。

Undefined behavior

未定义的行为。如果程序违反(或者超出) C 标准的规则定义,其执行的结果是无法预料的,换言之,对于这段语句,编译器不用理解(编译器可以不管它,也可以做任何事,包括让你女盆友怀孕 —— bumfod)可以做任何方式的理解,因此得到任何结果都是有可能的。例如,整数溢出就是一个 undefined behavior。

例如,对于如下代码

#include 
using namespace std;
int main()
{
    int n=1;
    cout<< n << " " << (n = n - 3) << " " << (n = n + 2);
    return 0;
}

g++ (i686-posix-dwarf-rev2, Built by MinGW-W64 project) 7.1.0 的编译运行结果为 1 -2 0,而g++ (GCC-6.3.0-1) 6.3.0 的结果为 0 0 0
“modify 和 read 之间没有 sequential point 就是 undefined behavior” —— bumfod.

Unspecified behavior

未明确的行为。对于有歧义的语句,可以按照任何可行的方式来解释。例如,函数在计算其参数时的顺序(求值顺序)就是一个 unspecified behavior,程序以任何顺序计算都可以。除此之外,形如 i = i+++i++; 的值也算是 unspecified behavior。因此我们要注意,在实际情况中不要使用依赖编译器具体实现的代码!

C 编程求出变量类型的内存空间长度

题目

编程求出 char、short、int、long、long long、float、double、long double 变量类型的内存空间长度。

题解

sizeof 运算符

sizeof(类型)

返回 类型 的对象表示的字节数

sizeof 表达式

返回当 表达式 求值时所返回的类型的对象的表示的字节数

引用自 sizeof 运算符

示例代码如下,其余的可以以此类推。
更正:由于 sizeof 是数据类型空间长度计算符号,所以可以直接求出变量类型的数据类型空间长度无需单独定义变量。修改后的题解如下。(感谢上理计科 夏耘 老师指正!)

printf("%u\n", sizeof(int));

原题解如下:

int a;
printf("%u\n", sizeof(a));

注:sizeof() 返回值为 size_t 类型,而 size_t 的类型和编译器有关,是不确定的。唯一可以确定的是这是个 unsigned 类型。在此处我们使用 %u 来输出。(C99 和 C11 提供 %zd 转换说明匹配 size_t,一些不支持 C99 和 C11 的编译器可用 %u%lu 代替。)

二进制思想

我们已知:1 byte = 8 bits。又知,对于题目中所述的变量类型,一般通过一个单独的 bit 来表示数值的正负,为 0 时表示正,为 1 时表示负。这就意为着,当所有的 bit 全为 1 时,值为负数且绝对值最大。那么我们可以构造一个循环来计算 2 的 n 次幂并存入变量,当完成最后一次循环时,最高位比特为 1,数值溢出变量范围,变为负值。此时 n+1 为该变量类型内存空间所占比特数。通过关系 1 byte = 8 bits 即可求得对应的字节数。 示例代码如下,其余的可以以此类推。注:因为完成了最后一次循环后 i 进行了自增,因此实际输出的 n 即为刚刚我们所提到的 n+1。

char t = 1;
int i = 1;
for (; t > 0; i++)
    t *= 2;
printf("%d\n", i);