JavaScript is required to for searching.
跳过导航链接
退出打印视图
Oracle Solaris Studio 12.3:C 用户指南     Oracle Solaris Studio 12.3 Information Library (简体中文)
search filter icon
search icon

文档信息

前言

1.  C 编译器介绍

2.  特定于 C 编译器实现的信息

3.  并行化 C 代码

4.  lint 源代码检验器

5.  基于类型的别名分析

6.  转换为 ISO C

6.1 基本模式

6.1.1 -Xc

6.1.2 -Xa

6.1.3 -Xt

6.1.4 -Xs

6.2 新式函数原型

6.2.1 编写新代码

6.2.2 更新现有代码

6.2.3 混合使用的注意事项

6.3 带有可变参数的函数

6.4 提升:无符号保留与值保留

6.4.1 一些历史背景

6.4.2 编译行为

6.4.3 示例:强制类型转换的使用

6.4.4 示例:相同的结果,不发出警告

6.4.5 整型常量

6.4.6 示例:整形常量

6.5 标记化和预处理

6.5.1 ISO C 转换阶段

6.5.2 旧 C 转换阶段

6.5.3 逻辑源代码行

6.5.4 宏替换

6.5.5 使用字符串

6.5.6 标记粘贴

6.6 const 和 volatile

6.6.1 仅适用于 lvalue 的类型

6.6.2 派生类型中的类型限定符

6.6.3 const 意味着 readonly

6.6.4 const 用法示例

6.6.5 volatile 用法示例

6.7 多字节字符和宽字符

6.7.1 亚洲语言需要多字节字符

6.7.2 编码变化 (Encoding Variations)

6.7.3 宽字符

6.7.4 C 语言特征

6.8 标准头文件和保留名称

6.8.1 标准头文件

6.8.2 保留供实现使用的名称

6.8.3 保留供扩展使用的名称

6.8.4 可安全使用的名称

6.9 国际化

6.9.1 语言环境

6.9.2 setlocale() 函数

6.9.3 更改的函数

6.9.4 新函数

6.10 表达式中的分组和求值

6.10.1 表达式定义

6.10.2 K&R C 重新整理许可证

6.10.3 ISO C 规则

6.10.4 括号用法

6.10.5 As If 规则

6.11 不完全类型

6.11.1 类型

6.11.2 完成不完全类型

6.11.3 声明

6.11.4 表达式

6.11.5 使用原因

6.11.6 示例:不完全类型

6.12 兼容类型和复合类型

6.12.1 多个声明

6.12.2 分别编译兼容性

6.12.3 单编译兼容性

6.12.4 兼容指针类型

6.12.5 兼容数组类型

6.12.6 兼容函数类型

6.12.7 特殊情况

6.12.8 复合类型

7.  转换应用程序以适用于 64 位环境

8.  cscope:交互检查 C 程序

A.  按功能分组的编译器选项

B.  C 编译器选项参考

C.  实现定义的 ISO/IEC C99 行为

D.  C99 的功能

E.  实现定义的 ISO/IEC C90 行为

F.  ISO C 数据表示法

G.  性能调节

H.  Oracle Solaris Studio C:K&R C 与 ISO C 之间的差异

索引

6.2 新式函数原型

1990 ISO C 标准在语言方面的最大变化是借鉴了 C++ 语言的函数原型。通过为每个函数指定其参数的数目和类型,各常规编译获得对每个函数调用的形参 (argument) 和实参 (parameter) 检查(类似于 lint 的参数检查)的益处,而参数自动转换(就如同赋值一样)为函数预期的类型。由于存在许许多多可以而且应该转换为使用原型的现有 C 代码行,因此 1990 ISO C 标准包括了控制旧式和新式函数声明混合的规则。

1999 ISO C 标准使得旧式函数声明被废弃。

6.2.1 编写新代码

编写全新的程序时,在头文件中使用新式函数声明(函数原型),在其他 C 源文件中使用新式函数声明和定义。但是,如果有人将代码移植到某个系统而该系统使用的编译器是 ISO C 之前的版本,请在头文件和源文件中使用宏 __STDC__(仅为 ISO C 编译系统定义)。有关示例,请参阅6.2.3 混合使用的注意事项。

只要同一对象或函数的两个不兼容声明处于同一作用域中,符合 ISO C 的编译器就必须发出诊断。如果使用原型来声明和定义所有函数,并且相应的头文件包含在正确的源文件中,则所有调用应与函数的定义一致。此协议消除一种最常见的 C 编程错误。

6.2.2 更新现有代码

如果您已有一个应用程序并且想利用函数原型,则有多种更新选项可供选择,具体取决于您要更改的代码量:

  1. 重新编译而不进行任何更改。

    如果使用 – v 选项进行调用,即使不更改代码,编译器也会对参数类型和数目的不匹配发出警告。

  2. 仅在头文件中增加函数原型。

    包括所有全局函数调用。

  3. 在头文件中增加函数原型,并使每个源文件以其局部(静态)函数的函数原型开头。

    包括所有函数调用,但此方法需要在源文件中为每个局部函数键入两次接口。

  4. 更改所有函数声明和定义以使用函数原型。

对于大多数程序员,第 2 种选择和第 3 种选择可能最具成本效益。遗憾的是,这些选项要求程序员详细了解混合新旧风格的规则。

6.2.3 混合使用的注意事项

为了使函数原型声明适用于旧式函数定义,两者都必须使用 ISO C 术语指定功能相同的接口或必须具有兼容类型。

对于具有可变参数的函数,不能混合 ISO C 的省略号表示法和旧式 varargs() 函数定义。对于具有固定数目参数的函数,可以指定在先前实现中传递的参数的类型。

在 K&R C 中,根据缺省参数提升,就在将每个参数传递到被调用函数之前对其进行转换。这些提升规定,所有比 int 短的整数类型均要提升为 int 长度,并且任何 float 参数均要提升为 double,从而简化了编译器和库。函数原型更具有表现力,指定的参数类型即为传递给函数的类型。

因此,如果为现有的(旧式)函数定义编写函数原型,则函数原型不应包含具有以下任意类型的任何参数:char、signed char、unsigned char、float、short、signed short、unsigned short。

在编写原型方面仍存在两个复杂因素:typedef 名称以及短的无符号类型的提升规则。

如果旧式函数中的参数是使用 typedef 名称(如 off_t 和 ino_t)声明的,则必须知道 typedef 名称指定的类型是否受到缺省参数提升的影响。对于这两个名称,off_t 是 long 类型的,因此可以在函数原型中使用它;ino_t 过去是 unsigned short 类型的,因此如果在原型中使用它,则编译器将发出诊断,因为旧式定义和原型指定的接口不同且不兼容。

确定应使用什么替代 unsigned short 比较复杂。K&R C 和 1990 ISO C 编译器之间最大的不兼容性是用于将 unsigned char 和 unsigned short 展宽为 int 值的提升规则。(请参见6.4 提升:无符号保留与值保留。)与此旧式参数匹配的参数类型取决于编译时使用的编译模式:

最佳方法是将旧式定义更改为指定 int 或 unsigned int 并使用函数原型中的匹配类型。如有必要,在输入函数后,您可以始终将其值赋给具有更窄类型的局部变量。

请注意原型中 ID 的使用,它可能受预处理的影响。请看以下示例:

#define status 23
void my_exit(int status);   /* Normally, scope begins */
                            /* and ends with prototype */

不要将函数原型与包含窄类型的旧式函数声明混合在一起。

void foo(unsigned char, unsigned short);
void foo(i, j) unsigned char i; unsigned short j; {...}

正确使用 __STDC__ 可生成一个可用于新旧编译器的头文件:

header.h:
    struct s { /* .  .  .  */ };
    #ifdef __STDC__
       void errmsg(int, ...);
       struct s *f(const char *);
       int g(void);
    #else
      void errmsg();
      struct s *f();
      int g();
    #endif

以下函数使用原型,但仍可在较旧的系统中编译:

struct s *
#ifdef __STDC__
    f(const char *p)
#else
    f(p) char *p;
#endif
{
    /* .  .  .  */
}

以下示例说明了更新的源文件(与上面的选项 3 相同)。局部函数仍使用旧式定义,但包括了原型供较新的编译器使用:

source.c:
   #include “header.h”
      typedef /* .  .  .  */ MyType;
   #ifdef __STDC__
      static void del(MyType *);
      /* .  .  .  */
      static void
      del(p)
      MyType *p;
      {
      /* .  .  .  */
      }
      /* .  .  .  */