c语言一些细节问题

最近遇到的一些小问题

typedef union
{
    int i;
    char c[4];
}un_t;

int main()
{
    int a = 0x12ff12ff;
    char *p = ((un_t)a).c;
    return 0;
}

第十行这种写法 char *p = ((un_t)a).c; c89会报invalid use of non-lvalue array的错误.
如果改为 char *p = ((un_t)a).c + 0; 则是报错invalid operands to binary + (have ‘char[4]’ and ‘int’) .
但c99是支持这种写法的(以上两种).

另一个小问题是关于指针的加减运算.

int main()
{
    char str[] = "abcdefghijk";

    char *p1 = str + 5;
    char *p2 = p1 + 3;

    char *p3 = str;

    char *p4;

    p4 = p3 + p2 - p1; //error
    p4 = p3 + (p2 - p1); //ok
    return 0;
}

第12行和13行虽然看上去是一回事, 结果也一样(可以通过强制转换通过编译)
但12行这样写会报错: invalid operands to binary + (have ‘char *’ and ‘char *’), 也就是指针之间不能相加
c标准规定, 指针的算术操作包括: (指针 – 指针), (指针 + 整数), (指针 – 整数), ++指针, 指针++, –指针, 指针–
这个问题虽然以前看书时留意过, 也许是觉得这种东西理所当然吧, 心想谁会在这里犯错误, “理所当然”地成为了一个被忽略的细节..