一个编译器的小陷阱
有时候在一个平台运行正确的程序,在另一个平台就会出问题。在平台移植中,最常见的问题可能就是字节序和对齐这类问题了。本文记录的是我以前碰到过的一个小陷阱。看看这段代码的输出应该是什么?
#include "stdio.h"
char do_something(int *p)
{
*p = 5;
return 'x';
}
void test1(void)
{
char s[] = "abcdef";
int index = 0;
s[index] = do_something(&index);
printf("%s\n", s);
}
int main(void)
{
test1();
return 0;
}
如果我们使用VC编译器或ARM编译器,它的输出是abcdex。如果我们使用gcc,它的输出是xbcdef。关键在于这句:
s[index] = do_something(&index);
等号左侧的index在等号右侧被改变了。VC和ARM编译器使用改变后的index(值为5),gcc编译器使用改变前的index(值为0)。我实际碰到的代码当然要复杂的多,在上万行代码中找到这行代码可不是一件让人愉快的事情。其实,解决此类编译器陷阱的最好方法就是:不要写可能产生歧义的语句。从本例我们应该记住:
- 在赋值语句中,等号左侧使用的数组索引或指针偏移在等号右侧不应被改变。
你碰到过类似的陷阱吗?
分享到:
相关推荐
标题 "C语言子集编译器" 暗示了我们正在讨论的是一个专注于C语言特定子集的编译器项目。编译器是将高级编程语言(如C语言)转换为机器可执行代码的软件工具。这个项目的重点可能是简化或优化C语言的某些部分,以适应...
本文通过一个具体的案例来探讨编译器优化所带来的潜在问题及其解决方案。 #### 案例背景 案例中的开发者使用了KE的驱动库以及Keil作为开发环境。为了实现一个简单的延时功能,编写了一段代码,期望通过中断服务程序...
**Arm编译器参考指南** 是一个详细的文档,旨在为用户提供有关 Arm 编译器的深入理解,特别是 RealView 编译工具 (RVCT) 的使用方法及其实现细节。这份指南包含了大量重要的信息,对于希望使用 ARM 架构进行高效编程...
而一个包围在双引号中的字符串,只是编写一个有双引号之间的字符和一个附加的二进制值为零的字符所初始化的一个无名数组的指针的一种简短方法。 在理解C语言的语法和语义时,需要注意以下几点: 2.1 理解声明:每...
7. **移植与兼容性**:讲解如何将代码从一个平台移植到另一个平台,以及如何确保代码在不同版本的编译器下具有良好的兼容性。 8. **故障排查与最佳实践**:提供常见错误的解决方案,以及一些编译和编程的最佳实践,...
1.3 C 编译器读入字符使用贪心法,从左到右一个一个读入,判断已读入的字符串是否可以组成一个符号。 1.4 整型常量第一个字符是 0,就会被视为八进制数。 1.5 单引号括起的一个字符代表一个 int 整数,双引号括起...
总结起来,交叉编译器4.4.3版本arm-linux是一个强大的工具,它简化了在非ARM平台上构建ARM架构Linux系统软件的过程。理解其工作原理和使用方法是提升嵌入式系统开发和服务器运维效率的关键。通过合理配置环境,结合...
假设有一个包含多个“/*”和“*/”的表达式,如果编译器支持嵌套注释,则该表达式可能被解释为有效的代码;但如果编译器不支持嵌套注释,则表达式可能会被错误地解析。 **示例:** ``` /*/*/0*/**/1 ``` **解析:...
GCC(GNU Compiler Collection)是GNU项目的一个核心组件,它是一个开源的、跨平台的编译器套件,用于将C、C++、Objective-C、Fortran、Ada、Go等多种编程语言编写的源代码翻译成可执行文件。GCC最初由Gnu创始人...
- 对于返回值以及参数类型定义不明确的函数,比如返回类型为int的函数返回一个指针,可能会导致编译器警告或错误。 5. 关于内存操作: - 对于字符串和动态分配的内存,使用strncpy()代替strcpy()可以避免溢出,当...
Dewhurst所著的一本关于C++编程的书籍,专注于揭示在C++编程过程中可能遇到的各种问题和陷阱。这本书深入浅出地讲解了可能导致程序错误或难以维护的因素,旨在帮助程序员避免这些常见的编程误区。 首先,我们要...
2. **GNU风格的内联汇编**:介绍了另一种常见风格——GNU风格的内联汇编,它在GCC等编译器中广泛应用。 #### 七、使用外部汇编器 1. **静态链接库**:讨论了如何将汇编代码编译成静态链接库,以及如何在项目中使用...
**问题描述:** `switch-case` 结构中 case 之间的穿透问题是一个常见的陷阱。 **解析:** - 在 C 语言中,如果没有显式地加入 `break` 语句,控制流会继续执行下一个 `case`。 - 例如: ```c switch (color) { ...
例如,如果一个返回`int`类型的函数`min()`被调用,而没有在其调用前声明,那么编译器默认该函数返回`int`类型。即使`min()`实际上返回的是浮点数,如`float`,编译器也不会报错。这会导致类型不匹配,可能产生意外...
此外,如果在同一个源文件中先声明了函数min,然后在main函数之前定义了该函数,但在main函数中调用min函数时却错误地只提供了部分参数,编译器会在编译阶段就报错,因为这时编译器已经知道了min函数的声明。...
- **final**:这是一个非常重要的关键字,当一个类被声明为final时,意味着它不能被继承。同样地,如果一个方法被声明为final,则不能在子类中被重写(override)。final也可以用来修饰变量,这样的变量一旦赋值后就...
但如果在不允许嵌套注释的编译器上使用相同的代码,由于编译器会忽略掉第一个“/*”之后的所有内容,所以这个表达式会被解析为`/*/*/0*/`,最终结果是0。这样的差异可能会导致程序在不同的编译环境中表现不一致,...
标题中的“意外错误陷阱处理动态链接库示例VB源码”指的是一个VB(Visual Basic)编程项目,它包含了处理程序中可能出现的意外错误的机制。动态链接库(DLL)是Windows操作系统中的一种共享代码的方式,它允许多个...