C语言关于include顺序不同导致编译结果不同的问题

目录
  • 编译环境
  • 问题简化
  • 问题分析
  • 总结

  今天遇到了因为include顺序不同而编译结果不同的问题。归根结底还是自己写代码的习惯不好导致的。

编译环境

  既然要写就多写点吧。最近又开始做TI的DSP C6455相关的开发了。之前的文章里有写到,TI提供有一个CSL库,但是比较老,输出的格式是COFF,而现在一般是ELF。如果做一些新的开发的话,建议重新编译CSL库,并选择输出为ELF格式。

  C6000 DSP的编译工具链目前主要有7.4和8.3版本。8.0以上的版本不再支持C6455了,所以我目前用的CGT版本是7.4.24,7.4版本的应该都差不多,因为文档都是一样的。

问题简化

  实际工程中包含大大小小的文件很多,头文件的include层层嵌套。所以我在这里为了说明关键问题,把我实际遇到的问题做了简化。整个工程包含三个文件main.cpp, CData.cpp和CData.hpp。源码如下:

// main.cpp
/* Scenario 1: it doesn't work */
#include "csl_types.h"
#include "CData.hpp"
/* Scenario 2: it does work */
// #include "CData.hpp"
// #include "csl_types.h"
int main(void) {
    return 0;
}
// CData.cpp
#include "CData.hpp"
// CData.cpp
#ifndef CDATA_HPP_
#define CDATA_HPP_
#include <assert.h>
#include <stdlib.h>
class CData {
public:
CData(): m_pData(NULL), m_nCnt(0) {}
CData(int nCnt): m_nCnt(nCnt) {
    m_pData = new int[nCnt];
    assert(m_pData != NULL);
}
~CData(){
    if(m_pData){
        delete[] m_pData;
        m_pData = NULL;
    }
}
protected:
    int *m_pData;
    int m_nCnt;
};
#endif

  实际上的现象就是main.cpp中include了两个头文件,它们include的前后顺序不同,导致了编译结果不同。在第一种情况下编译得到这样的结果:

  而在第二种情况下就是能够正常完成编译。

问题分析

a value of type "void *" cannot be used to initialize an entity of type "int *"
a value of type "void *" cannot be assigned to an entity of type "int *"

  报错提示的问题和NULL有关,大概意思是NULL是一个void *的类型,不能把它赋给其他类型的变量。但可以看到,单独编译CData.cpp是没有出现问题的。而在编译main.cpp的时候,因为先include了csl_types.h,导致改变了NULL的定义,所以出了问题。

  查找有NULL相关的定义的文件可以找到:

// stdlib.h
#ifndef NULL
#define NULL 0
#endif
// csl_types.h
#ifndef NULL
#define NULL ((void*)0)
#endif
// xdc/std.h
#undef NULL
#if defined(__cplusplus) || !defined(xdc__strict)
#define NULL 0
#else
#define NULL ((void *)0)
#endif

  stdlib.h大家应该都比较熟悉,是标准库。csl_types.h是在用CSL的时候会不经意间包含的一个头文件。还有xdc/std.h是在用RTSC时可能会用到的头文件。这几个文件里都有关于NULL的定义。

  我这次遇到的问题就是因为前两个文件include的前后顺序不同,NULL定义的情况也就不同了。而第三个文件感觉比较好,会先undef NULL,然后再重新define,应该可以一定程度上避免这个问题。但是第三个文件中有些类型的定义也会和csl_types.h产生冲突,所以用起来还是要注意。

总结

  这次虽然两个头文件include的顺序引发的问题。但是归根结底我觉得还是因为我直接在头文件里做类(CData)的定义,而没有把定义放在cpp文件中。如果把方法的具体实现放在源文件里,然后把那些头文件中的include放到源文件里去,应该可以一定程度上避免这种问题的出现。

  实际工程中遇到这类问题,往往include有多层,很难发现,所以还是应该要有一个良好的编程习惯!

到此这篇关于C语言关于include顺序不同导致编译结果不同的问题的文章就介绍到这了,更多相关C语言include顺序内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 浅谈C语言中include""与include<>的区别

    新建控制台应用程序 Win32 Application和Win32 Console Application 都是工作在32位Windows环境的程序.其中: (1)Win32 Application就是普通的常见的窗口应用程序,当然有的界面做得比较个性化,比如圆形的.不规则形状的-它们都是所谓的GUI(Graphics User Interface图形用户接口),我们可以通过鼠标点击来完成控制.Win32 Application是为你开发windows应用程序所准备的,程序以WinMain()为

  • C语言关于include顺序不同导致编译结果不同的问题

    目录 编译环境 问题简化 问题分析 总结   今天遇到了因为include顺序不同而编译结果不同的问题.归根结底还是自己写代码的习惯不好导致的. 编译环境   既然要写就多写点吧.最近又开始做TI的DSP C6455相关的开发了.之前的文章里有写到,TI提供有一个CSL库,但是比较老,输出的格式是COFF,而现在一般是ELF.如果做一些新的开发的话,建议重新编译CSL库,并选择输出为ELF格式.   C6000 DSP的编译工具链目前主要有7.4和8.3版本.8.0以上的版本不再支持C6455了

  • C语言实现动态顺序表的实现代码

    C语言实现动态顺序表的实现代码 顺序表是在计算机内存中以数组的形式保存的线性表,是指用一组地址连续的存储单元依次存储数据元素的线性结构.线性表采用顺序存储的方式存储就称之为顺序表.顺序表是将表中的结点依次存放在计算机内存中一组地址连续的存储单元中. 静态实现:结构体内部只需两个成员,其中一个为固定大小(MAX)的数组,用来存放我们的数据.数组大小我们可以通过在头文件中改变MAX的值来改变. 动态实现:在内存中开辟一块空间,可以随我们数据数量的增多来扩容. 来看看动态的顺序表实现: 1.seqli

  • C语言数据结构之顺序数组的实现

    C语言数据结构之顺序数组的实现 以下为展示顺序数组的示例: 1.用C语言实现的版本 #include<stdio.h> /* EOF(=^Z或F6),NULL */ #include<math.h> /* floor(),ceil(),abs() */ #include<stdlib.h> /*申请和释放内存*/ #include<stdarg.h> /*可变参数*/ #define OK 1 //成功标志 #define ERROR 0 //错误标志 #d

  • C语言实现静态顺序表的实例详解

    C语言实现静态顺序表的实例详解 线性表 定义一张顺序表也就是在内存中开辟一段连续的存储空间,并给它一个名字进行标识.只有定义了一个顺序表,才能利用该顺序表存放数据元素,也才能对该顺序表进行各种操作. 接下来看看静态的顺序表,直接上代码: SeqList.h #define _CRT_SECURE_NO_WARNINGS 1 #ifndef __SEQLIST_H__ #define __SEQLIST_H__ #include <stdio.h> #include <stdlib.h&g

  • C语言实现的顺序表功能完整实例

    本文实例讲述了C语言实现的顺序表功能.分享给大家供大家参考,具体如下: seqlist.h #ifndef __SEQLIST_H__ #define __SEQLIST_H__ #include<cstdio> #include<malloc.h> #include<assert.h> #define SEQLIST_INIT_SIZE 8 #define INC_SIZE 3 //空间增量的大小 typedef int ElemType; typedef struc

  • C语言数据结构之顺序表和单链表

    一.顺序表的创建.删除和插入 #define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> struct sqlist { int date[10]; int length; }; void InitList(sqlist& L) { for (int i = 0;i < 10;i++) { L.date[i] = 0; } L.length = 0; } void charu(sqlist& L) { for (int j =

  • C语言如何用顺序栈实现回文序列判断

    我是采用了两个栈值得比较大小判断得(可能比较浪费空间但是代码我感觉简单一点) 首先是定义一个栈的结构元素,由于是字符串类型就直接定义一个char的数组就可以:. typedef struct stack { char data[MAX_SIZE]; //储存字符串// int top; //记录栈顶// }SeqStack; 下来就是初始化,我这里是用的耿国华老师的方法就直接给一个top元素指向栈顶,传入的指针地址:. void Initstack(SeqStack *S) //初始化栈,让to

  • 新手向超详细的C语言实现动态顺序表

    目录 一.各个函数接口的实现 1.1 不太好''李姐''的"容量检测函数" 1.2 在任意位置插入的函数"坑!" 1.3 在任意位置删除数据的函数 1.4 其余简单的接口函数 二.顺序表结构体声明与定义 三.头文件的调用 一.各个函数接口的实现 1.1 不太好''李姐''的"容量检测函数" 对顺序表进行插入数据时,需要判断顺序表的容量是否充足,增加数据的同时需要反复地检测容量,所以推荐直接将以上步骤封装成一个函数. 函数实现算法:若容量大小 ==

  • C语言 超详细顺序表的模拟实现实例建议收藏

    目录 概念及结构 接口实现 1 顺序表的动态存储 2 顺序表初始化 3 顺序表的销毁 4 顺序表的尾插 5 顺序表的尾删 6 顺序表的头插 7 顺序表的头删 8 顺序表容量的检查与扩容 9 顺序表任意位置的插入 10 顺序表任意位置的删除 11 顺序表的打印 12 顺序表元素的查找 13 顺序表元素的修改 概念及结构 顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储.在数组 上完成数据的增删查改. 顺序表一般可以分为: 静态顺序表:使用定长数组存储元素,元素

  • C语言深入浅出讲解顺序表的实现

    目录 1.线性表 2.顺序表 2.1 概念及结构 2.2 提供接口 2.3 接口实现 今天起开始编写数据结构中的各种数据结构及算法的实现,说到顺序表,我们首先得了解下线性表. 1.线性表 线性表(linear list)是n个具有相同特性的数据元素的有限序列. 线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表.链表.栈.队列.字符串… 线性表在逻辑上是线性结构,也就说是连续的一条直线.但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储. 2.顺序表

随机推荐