c函数编译符号表
1. c语言程序编译后产生哪些类型的文件这些文件的作用是什么
1、以GCC编译器为例,可以分为四步。
第一步是预处理,包括语法检查等工作。
gcc
-P
abc.c
第二步由源程序生产汇编语言代码。
gcc
-S
abc.c
会生成abc.s文件,这个文件里就是汇编代码。
第三步编译器生成目标代码,一个源文件生成一个目标代码。
gcc
-c
abc.c
会生成abc.o
第四步连接器从目标代码生成可执行文件。
gcc
abc.o
2、目标代码包括机器码和符号表(函数及变量名)。连接器的主要作用是通过符号表在库文件和其他模块中找到在目标代码中引入或未定义的符号(函数及变量名),将几个目标代码合成可执行文件。
2. 如何查看ndk编译的动态库符号表
$ /path/to/ndk/buid/prebuilt/windows/arm-eabi-4.4.0/bin/arm-eabi-nm libs/armeabi/libsanangeles.so
00003600 T java_com_example_SanAngeles_DemoGLSurfaceView_nativePause
00003638 T Java_com_example_SanAngeles_DemoRenderer_nativeDone
0000367c T Java_com_example_SanAngeles_DemoRenderer_nativeInit
000035b4 T Java_com_example_SanAngeles_DemoRenderer_nativeRender
00003644 T Java_com_example_SanAngeles_DemoRenderer_nativeResize
00007334 a _DYNAMIC
0000740c a _GLOBAL_OFFSET_TABLE_
复制代码
这里可以看到几乎所有的函数名全局变量名都会被导出。其中有Java_com_example_SanAngeles_为前缀的JNI接口函数,有importGLInit这些普通函数,有freeGLObject这些局部(static)函数,还有sStartTick等全局变量名。其实在这个动态发布的时候,只需要导出java_com_开头的jni函数就可以了,里面这些细节函数名完全不需要暴露出来。
如何做到这一点呢?首先,我们需要了解gcc新引进的选项-fvisibility=hidden,这个编译选项可以把所有的符号名(包括函数名和全局变量名)都强制标记成隐藏属性。我们可以在Android.mk中可以通过修改LOCAL_CFLAGS选项加入-fvisibility=hidden来做到这一点,这样编译之后的.so看到的符号表为:
000033d0 t Java_com_example_SanAngeles_DemoGLSurfaceView_nativePause
00003408 t Java_com_example_SanAngeles_DemoRenderer_nativeDone
0000344c t Java_com_example_SanAngeles_DemoRenderer_nativeInit
00003384 t Java_com_example_SanAngeles_DemoRenderer_nativeRender
00003414 t Java_com_example_SanAngeles_DemoRenderer_nativeResize
00007104 a _DYNAMIC
3. c语言程序的运行过程中在哪些过程中会产生文件
编译过程会产生.o文件(目标文件)链接后产生可执行文件。
目标代码包括机器码和符号表(函数及变量名)。连接器的主要作用是通过符号表在库文件和其他模块中找到在目标代码中引入或未定义的符号(函数及变量名),将几个目标代码合成可执行文件。
不同的系统,产生的文件不一样;
win:
->.obj目标文件
->.obj目标文件->.exe可执行文件
->.rc
(3)c函数编译符号表扩展阅读:
解释方式下,计算机对高级语言书写的源程序一边解释一边执行,不能形成目标文件和执行文件。
编译方式下,首先通过一个对应于所用程序设计语言的编译程序对源程序进行处理,经过对源程序的词法分析、语法分析、语意分析、代码生成和代码优化等阶段将所处理的源程序转换为用二进制代码表示的目标程序,通过连接程序处理将程序中所用的函数调用、系统功能调用等嵌入到目标程序中,构成一个可以连续执行的二进制执行文件。
调用这个执行文件就可以实现程序员在对应源程序文件中所指定的相应功能。
4. c语言编程
//计划做的脚本引擎的一部分
//参考的 C++编程艺术
//总地来说会有一些难度
//我的是C++应该会给你一些启发
//TypeDef.h
#include "windows.h"
#ifndef B_TYPE_DEF_H
#define B_TYPE_DEF_H
const int MAX_T_LEN = 128;//可以分析的最大符号长度(同时决定了一个字符变量的最大长度为128字节)
const int MAX_ID_LEN = 31;//允许的最大的标识长度(一个标识符是指一个变量名或函数名)
const int MAX_BUF_LEN = 1024;//解释缓冲区1024字节
const int NUM_PARAMS = 32;//最大参数数目
const int MAX_DIM_NUM = 65536//数组最大维数
//需要分析的所有东西
enum Token_Item { UNDEF=1, //未定义
E_TEMP,//当模板使用
E_CHAR,//char关键字
E_INT,//int关键字
E_FLOAT,//float关键字
E_SWITCH,//switch关键字
E_CASE,//case关键字
E_IF,//if关键字
E_ELSE,//else关键字
E_FOR,//for关键字
E_DO,//do关键字
E_WHILE,//while关键字
E_BREAK,//break关键字
E_RETURN,//return关键字
E_COUT,//cout关键字
E_CIN,//cin关键字
LBLOCK, //{
RBLOCK,//}
DOU,//,
EOS,//;
MAO,//:
SFEN,//'已舍弃,不含'分析
LT,//<
LE,//<=
GT,//>
GE,//>=
EQ,//==
NE,//!=
FF,//.
LK,//(
NOT,//!
INC,//++
DEC,//--
ADD,//+
SUB,//-
RK,//)
LZK,//[
RZK,//]
LS,//<<
RS,//>>
ASS,//=
AND,//&&
OR,//||
MUL,//*
DIV,///
MOD,//%
POW,//^
NUMBER, //数字
IDENTIFIER,//标识
STRING,//字符串
END//文件结束
};//需要分析的全部符号
enum Token_Type{
UNK,//未知类型
KEY,//关键字
FJF,//分界符
CMP,//比较运算符
OPE,//运算符
NUM,//数字
IDE,//标识符
STR,//字符串
NON,//结束符号
UDF//未定义
};
typedef struct Token_Table{//符号表
char name[MAX_T_LEN];
Token_Item token;
Token_Type type;
} TOKEN_TABLE,*PTOKEN_TABLE;
enum error_msg //错误类型
{ SYNTAX=1000, NO_EXP, NOT_VAR, DUP_VAR, DUP_FUNC,
SEMI_EXPECTED, UNBAL_BRACES, FUNC_UNDEF,
TYPE_EXPECTED, RET_NOCALL, PAREN_EXPECTED,
WHILE_EXPECTED, QUOTE_EXPECTED, DIV_BY_ZERO,
BRACE_EXPECTED, COLON_EXPECTED,FAIL_OPEN,ERROR_SIZE,
NO_MAIN,ERROR_ASSIGN,ERROR_RZK,ERROR_DIM};
class InterpExc { //错误类
error_msg err;
public:
InterpExc(error_msg e) { err = e; }
error_msg get_err() { return err; }
};
enum Vars{类型
V_Int,
V_Float,
V_String,
V_pInt,
V_pFloat,
V_pString,
V_Udef
};
#endif
#ifndef V_NULL
#define V_NULL (-1)
#endif
//Cfenxi.h
#include "TypeDef.h"
#include <iostream>
#include <vector>
#include <stack>
#include <algorithm>
#include <string>
using namespace std;
//Fenxi类说明
//curr_pt始终指向将要分析的地址
//prev_pt为前一个分析的地址
//可以使用函数GotoPt来改变当前分析地址
//分析结果放在变量stoken,item,type
//在Cfenxi.cpp中定义了一个文件级变量TOKEN_TABLE tokentable[];
//在使用的时候必须声明这个变量
#ifndef B_CFENXI_H
#define B_CFENXI_H
class Fenxi{
public:
char stoken[MAX_T_LEN+1];//分析出来的符号名
char buff[MAX_BUF_LEN+1];//缓冲区
Token_Item item;//分析出来的具体符号
Token_Type type;//符号大类
long curr_pt;//当前分析点
long prev_pt;//前一个分析点
char pFileName[256];//脚本文件名
PTOKEN_TABLE pTokenTable;//符号表
public:
Fenxi(){};
~Fenxi(){};
void Create(char*,PTOKEN_TABLE,int);//创建分析对象
void GetToken();//分析一步
void GotoPt(long);//跳分析点
void PutBack();//回退一个分析点
private:
int nTableItem;//分析表中的分析数目
long iFileLength;//脚本文件长度
int iBlock;//当前所在区块
int iYouBiao;//当前游标
char cbuff;//当前所指向的字符
char cbuff1;//超前搜索的字符
void MoveNext();//向下移动
void MovePrev();//向前移动
void LoadBlock();//装入一个块
long GetPt(int i,int n){return (long)(i*MAX_BUF_LEN+n);};//计算位置
bool KeyLookUp(char*,Token_Item &);//查找是不是关键词
bool isdelim(char);
};
//解释类
class var_value{
public:
char string_value[MAX_T_LEN+1];
int int_value;
float float_value;
Vars v_type;
public:
var_value()
{
int_value=0;
float_value=0;
string_value[0]=0;
v_type=Udef;
}
var_value(const var_value&);
set_type(Vars type){v_type=type;}
~var_value(){}
friend bool operator == (const var_value& _X, const var_value& _Y);
friend bool operator < (const var_value& _X, const var_value& _Y);
};
class temp_var_value{
public:
char string_value[MAX_T_LEN+1];
int int_value;
float float_value;
int p_int;
int p_float;
int p_string;
vector<int> dim;
Vars v_type;
public:
temp_var_value()
{
int_value=0;
float_value=0;
string_value[0]=0;
p_int=p_float=p_string=V_NULL;
v_type=Udef;
};
temp_var_value(const temp_var_value&);
temp_set_type(Vars type){v_type=type;}
~temp_var_value(){}
friend bool operator == (const temp_var_value& _X, const temp_var_value& _Y);
friend bool operator < (const temp_var_value& _X, const temp_var_value& _Y);
};
struct var_type { //变量类型
char var_name[MAX_ID_LEN+1]; // 变量名
Vars v_type;//数据类型
vector<var_value> value; //变量值
vector<int> v_dim;//变量维数
int v_max;//变量的最大数目
};
struct func_type {
char func_name[MAX_ID_LEN+1]; //函数名
Vars ret_type; //返回值类型
long loc; // 函数入口点,函数的入口点是指分析点指向函数括号后第一个字符
};
class Script{
public:
Fenxi theFx;//词法分析对象,负责对脚本文件的操作
char FileName[256];//脚本文件名
var_value ret_value;//返回值
bool breakfound;//中断
public:
Script(){};
~Script(){};
void Create(char*,PTOKEN_TABLE,int);//创建脚本对象
void ExecuteScript();//开始解释脚本
private:
void PreScan();//预扫描
void decl_global();//声明全局变量
long find_func(char*);//返回函数的入口点
void ItemToVar(Token_Item,Vars&);//根据一个项,得到相当的变量类型
void CallFun();//执行一个函数
void get_args();//得到函数的形式参数名
void Interp();//具体解释
private:
void eval_exp (var_value &value);
void eval_exp0(var_value &value);
void eval_exp1(var_value &value);
void eval_exp2(var_value &value);
void eval_exp3(var_value &value);
void eval_exp4(var_value &value);
void eval_exp5(var_value &value);
void eval_exp6(var_value &value);
void eval_exp7(var_value &value);
void eval_exp8(var_value &value);
bool is_var(char *s);
// 变量名,变量的维数,变量的值,变量的类型
void assign_var(char *var_name,int idx, var_value value);
void find_var_value(char *var_name,int idx,var_value& value);
int find_idx(vector<int>,vector<int>);// 计算[][]
void find_vector(vector<int> &);//读取[]
int cal_idx(vector<int>);
Vars is_var_type;//使用is_var的时候如果返回值是真那么这个变量存储了变量类型
public:
//每执行一个函数的时候就把进入前的局部变量数目
//放到函数结点栈,函数执行完的时候就根据栈里的
//数据改变局部函数表里的变量,从而实现变量的灵活使用
//同理块结点栈的原理也一样
//变量表
vector<var_type> global_vars; //全局变量表
vector<var_type> local_var_stack; //局部变量表(函数参数作为局部变量处理)
vector<func_type> func_table; //函数表
stack<int> func_call_stack;//函数结点栈
stack<int> nest_scope_stack;//块结点栈
};
#endif
//Fenxi.cpp
#include "CFenxi.h"
#include <cstring>
#include <cctype>
#include <fstream>
#include <cstdio>
#include <cmath>
using namespace std;
///////////////////////////////////////////////////////////////////////
/////////////////////////词法分析类的函数定义//////////////////////////
///////////////////////////////////////////////////////////////////////
extern TOKEN_TABLE tokentable[]={
"char",E_CHAR,KEY,
"int",E_INT,KEY,
"float",E_FLOAT,KEY,
"switch",E_SWITCH,KEY,
"case",E_CASE,KEY,
"if",E_IF,KEY,
"else",E_ELSE,KEY,
"for",E_FOR,KEY,
"do",E_DO,KEY,
"while",E_WHILE,KEY,
"break",E_BREAK,KEY,
"return",E_RETURN,KEY,
"cout",E_COUT,KEY,
"cin",E_CIN,KEY,
"{",LBLOCK,FJF,
"}",RBLOCK,FJF,
",",DOU,FJF,
";",EOS,FJF,
"<",LT,CMP,
"<=",LE,CMP,
">",GT,CMP,
">=",GE,CMP,
"==",EQ,CMP,
"!=",NE,CMP,
".",FF,OPE,
"(",LK,OPE,
")",RK,OPE,
"[",LZK,OPE,
"]",RZK,OPE,
"++",INC,OPE,
"--",DEC,OPE,
"<<",LS,OPE,
">>",RS,OPE,
"=",ASS,OPE,
"!",NOT,OPE,
"&&",AND,OPE,
"||",OR,OPE,
"+",ADD,OPE,
"-",SUB,OPE,
"*",MUL,OPE,
"/",DIV,OPE,
"%",MOD,OPE,
"^",POW,OPE,
};
var_value::var_value(const var_value& p)
{
int_value=p.int_value;
float_value=p.float_value;
strcpy(string_value,p.string_value);
v_type=p.v_type;
}
bool operator == (const var_value& _X, const var_value& _Y)
{
if (_X.v_type != _Y.v_type)
{
return false;
}
else
{
switch (_X.v_type)
{
case V_Float:
return (abs(_X.float_value - _Y.float_value) < 0.0001);
break;
case V_Int:
return (_X.int_value == _Y.int_value);
break;
case V_Int:
return !(strcmp(_X.string_value, _Y.string_value));
break;
default:
return false;
}
}
}
bool operator < (const var_value& _X, const var_value& _Y)
{
if (_X.v_type != _Y.v_type)
{
return false;
}
else
{
switch (_X.v_type)
{
case V_Float:
return (_X.float_value < _Y.float_value);
break;
case V_Int:
return (_X.int_value < _Y.int_value);
break;
case V_Int:
return !(strcmp(_X.string_value, _Y.string_value));
break;
default:
return false;
}
}
temp_var_value::temp_var_value(const temp_var_value& p)
{
int_value=p.int_value;
float_value=p.float_value;
strcpy(string_value,p.string_value);
p_int=p.p_int;
p_float=p.p_float;
p_string=p.p_string;
v_type=p.v_type;
}
void Fenxi::Create(char* p,PTOKEN_TABLE ptt,int n)
{
strcpy(pFileName,p);
ifstream fin(pFileName,ios::in|ios::binary);
fin.seekg(0,ios::end);
iFileLength=fin.tellg();
fin.close();
if(iFileLength==0)
throw InterpExc(ERROR_SIZE);
iBlock=0;
LoadBlock();
MoveNext();//指向第一个字符
iYouBiao=0;//置游标于文件头
curr_pt=0;
prev_pt=0;
cbuff=buff[0];//当前应该分析字符
cbuff1=buff[1];//超前搜索字符
pTokenTable=ptt;
nTableItem=n;//分析表设置
}
void Fenxi::MoveNext()
{
if(iYouBiao==MAX_BUF_LEN-1)//如果当前游标在缓冲区尾
{
iBlock++;
LoadBlock();
cbuff=buff[0];
cbuff1=buff[1];//超前搜索
}
else
{
iYouBiao++;
cbuff=buff[iYouBiao];
if(iYouBiao==MAX_BUF_LEN-1)//超前搜索
{
char temp[2];
temp[1]=0;
ifstream fin(pFileName,ios::in|ios::binary);
fin.seekg(MAX_BUF_LEN*(iBlock+1));
fin.read(temp,1);
int i=fin.gcount();
temp[i]=0;
fin.close();
cbuff1=temp[0];
}
else
cbuff1=buff[iYouBiao+1];
}
curr_pt=GetPt(iBlock,iYouBiao);
}
void Fenxi::MovePrev()
{
if(iYouBiao==0)//如果当前游标在缓冲区头
{
cbuff1=cbuff;//超前搜索
iBlock--;
LoadBlock();
iYouBiao=MAX_BUF_LEN-1;
cbuff=buff[iYouBiao];
}
else
{
cbuff1=cbuff;//超前搜索
iYouBiao--;
cbuff=buff[iYouBiao];
}
curr_pt=GetPt(iBlock,iYouBiao);
}
void Fenxi::PutBack()
{
GotoPt(prev_pt);
}
void Fenxi::LoadBlock()//装入一个块
{
ifstream fin(pFileName,ios::in|ios::binary);
fin.seekg(MAX_BUF_LEN*iBlock);
fin.read(buff,MAX_BUF_LEN);
int i=fin.gcount();
buff[i]=0;
iYouBiao=0;
fin.close();
}
void Fenxi::GotoPt(long pt)
{
if(pt/MAX_BUF_LEN==curr_pt/MAX_BUF_LEN)//如果是在同一个块内的话
{
curr_pt=pt;
iYouBiao=curr_pt-iBlock*MAX_BUF_LEN;
cbuff=buff[iYouBiao];
}
else//否则要重新装入内存
{
curr_pt=pt;
iBlock=curr_pt/MAX_BUF_LEN;
LoadBlock();
iYouBiao=curr_pt-iBlock*MAX_BUF_LEN;
cbuff=buff[iYouBiao];
}
if(iYouBiao==MAX_BUF_LEN-1)//超前搜索
{
char temp[2];
temp[1]=0;
ifstream fin(pFileName,ios::in|ios::binary);
fin.seekg(MAX_BUF_LEN*(iBlock+1));
fin.read(temp,1);
int i=fin.gcount();
temp[i]=0;
fin.close();
cbuff1=temp[0];
}
else
cbuff1=buff[iYouBiao+1];
}
void Fenxi::GetToken()
{
prev_pt=curr_pt;//保存前一个的位置
char *temp; //利用一个指针向字符里写内容
item=UNDEF;type=UDF;
temp = stoken;
*temp = '\0';
// 如果当前字符是空格且未到文件末
while(isspace(cbuff) && cbuff) MoveNext();
// 跳过行
while(cbuff == '\r') {
MoveNext();
MoveNext();
while(isspace(cbuff) && cbuff) MoveNext();
}
// 是否结尾
if(cbuff == '\0') {
*stoken = '\0';
item = END;
type=NON;
return ;
}
// 检查{}标识符
if(strchr("{}", cbuff)) {
stoken[0]=cbuff;
stoken[1]='\0';
type=FJF;
if(cbuff=='{')
item=LBLOCK;
else
item=RBLOCK;
MoveNext();//指向下一个字符
return ;
}
// 检查注释信息
if(cbuff == '/')
if(cbuff1 == '*') { // /*注释符
MoveNext();
MoveNext();
do { // 找到结尾
while(cbuff != '*') MoveNext();
MoveNext();
} while (cbuff != '/');
MoveNext();
GetToken();
return;
} else if(cbuff1 == '/') { // is a // CMPment
MoveNext();
MoveNext();
// Find end of CMPment.
while(cbuff != '\r' && cbuff != '\0') MoveNext();
if(cbuff == '\r') {MoveNext();MoveNext();}
GetToken();
return;
}
// 检查双操作符
if(strchr("!<>=+-&|", cbuff)) {
switch(cbuff) {
case '|':
if(cbuff1 == '|') {
MoveNext();MoveNext();
*temp = '|';
temp++;
*temp = '|';
temp++;
*temp = '\0';
item=OR;
type=OPE;
}
break;
case '&':
if(cbuff1 == '&') {
MoveNext();MoveNext();
*temp = '&';
temp++;
*temp = '&';
temp++;
*temp = '\0';
item=AND;
type=OPE;
}
break;
case '=':
if(cbuff1 == '=') {
MoveNext();MoveNext();
*temp = '=';
temp++;
*temp = '=';
temp++;
*temp = '\0';
item=EQ;
type=CMP;
}
break;
case '!':
if(cbuff1 == '=') {
MoveNext();MoveNext();
*temp = '!';
temp++;
*temp = '=';
temp++;
*temp = '\0';
item=NE;
type=CMP;
}
break;
case '<':
if(cbuff1 == '=') {
MoveNext();MoveNext();
*temp = '<';
temp++;
*temp = '=';
item=LE;
type=CMP;
}
else if(cbuff1 == '<') {
MoveNext();MoveNext();
*temp = '<';
temp++;
*temp = '<';
item=LS;
type=OPE;
}
else {
MoveNext();
*temp = '<';
item=LT;
type=CMP;
}
temp++;
*temp = '\0';
break;
case '>':
if(cbuff1 == '=') {
MoveNext();MoveNext();
*temp = '>';
temp++;
*temp = '=';
item=GE;
type=CMP;
} else if(cbuff1 == '>') {
MoveNext();MoveNext();
*temp = '>';
temp++;
*temp = '>';
item=RS;
type=OPE;
}
else {
MoveNext();
*temp = '>';
item=GT;
type=CMP;
}
temp++;
*temp = '\0';
break;
case '+':
if(cbuff1 == '+') {
MoveNext();MoveNext();
*temp = '+';
temp++;
*temp = '+';
temp++;
*temp = '\0';
item=INC;
type=OPE;
}
break;
case '-':
if(cbuff1 == '-') {
MoveNext();MoveNext();
*temp = '-';
temp++;
*temp = '-';
temp++;
*temp = '\0';
item=DEC;
type=OPE;
}
break;
}
if(*stoken) return;
}
// 其它运算符号
if(strchr("+-*^/=().[]|!%", cbuff)) {
type=OPE;
switch(cbuff){
case '+':
item=ADD;break;
case '-':
item=SUB;break;
case '*':
item=MUL;break;
case '/':
item=DIV;break;
case '=':
item=ASS;break;
case '(':
item=LK;break;
case ')':
item=RK;break;
case '[':
item=LZK;break;
case ']':
item=RZK;break;
case '.':
item=FF;break;
case '|':
item=UNDEF;type=UDF;break;
case '!':
item=NOT;break;
case '%':
item=MOD;break;
}
*temp = cbuff;
MoveNext();
temp++;
*temp = '\0';
return ;
}
// 分界符号
if(strchr(";,#:", cbuff)) {
type=FJF;
switch(cbuff){
case ';':
item=EOS;break;
case ',':
item=DOU;break;
case ':':
item=MAO;break;
}
*temp = cbuff;
MoveNext();
temp++;
*temp = '\0';
return ;
}
// 读取一个字符串
if(cbuff == '"') {
MoveNext();
while(cbuff != '"' && cbuff != '\r' && cbuff) {
// Check for \n escape sequence.
if(cbuff == '\\') {
if(cbuff1 == 'n') {
MoveNext();
*temp++ = '\n';
}
}
else if((temp - stoken) < MAX_T_LEN)
*temp++ = cbuff;
MoveNext();
}
if(cbuff == '\r' || cbuff == 0)
throw InterpExc(SYNTAX);
MoveNext(); *temp = '\0';
item=STRING;
type=STR;
return ;
}
// 读取一个数字
if(isdigit(cbuff)) {
while((cbuff>='0'&&cbuff<='9')||(cbuff=='.')) {
if((temp - stoken) < MAX_T_LEN)
*temp++ = cbuff;
MoveNext();
}
*temp = '\0';
item=NUMBER;
type=NUM;
return ;
}
// Read identifier or keyword.
if(isalpha(cbuff)) {
while(!isdelim(cbuff)) {
if((temp - stoken) < MAX_T_LEN)
*temp++ = cbuff;
MoveNext();
}
item=E_TEMP;
}
*temp = '\0';
// Determine if token is a keyword or identifier.
if(item == E_TEMP) { // convert to internal form
if(KeyLookUp(stoken,item)) type=KEY; // is a keyword
else {type = IDE;item=IDENTIFIER;}
}
if(type==UDF)
throw InterpExc(SYNTAX);
}
bool Fenxi::KeyLookUp(char *s,Token_Item &it){
int i;
// char *p;
// 转为小写字母
// p = s;
// while(*p) { *p = tolower(*p); p++; }
for(i=0; i<nTableItem; i++) {
if((tokentable[i].type==KEY)&&!strcmp(tokentable[i].name, s))
{
it=tokentable[i].token;
return true;
}
}
return false;
}
// 符号检查
bool Fenxi::isdelim(char c)
{
if(strchr(" !:;,+-<>/*^=().|&[]\"%", c) || c == 9 ||
c == '\r' || c == 0) return true;
return false;
}
5. c语言中“\”后加数字各是什么
一般是转义字符。
转义字符是C语言中表示字符的一种特殊形式。转义字符以反斜''开头,后面跟一个字符或一个八进制或十六进制数表示。转义字符具有特定的含义,不同于字符原有的意义,故称转义字符。示例如下:
charc1=''';//后面接一个特殊字符
charc2='110';//后面接一个三位的八进制数
charc3='x0d';//后面接一个两位的十六进制数
6. C/C++问题,数组问题,菜鸟求教,望高手指教:
第一个问题:当然是内存中。CPU中能够存储信息的只有相应的寄存器,其存储位数有限,但是存取速度极快(对CPU来说就是自己家的东西,可以信手拈来)。所以一般的分配没有特殊说明都是在内存中(仔细追究起来实在内存空间中的栈空间中。当然利用new,malloc,alloc等申请的就在堆中——其实也是内存中的一部分,可参考有关操作系统的书籍)。
第二个问题:内存的分配最后都是有操作系统来完成的。当然也需要用到MMU的配合。
第三、四问题:C++中规定定义数组时,数组的大小必须是一个常数,或者一个常量表达式(如3+4)等,常量表达式在编译阶段,编译器就能够计算出其结果,从而在编译过程中就能够将大小,如本题中的30,告知操作系统,来申请合适的内存大小。如果你非要细究系统是怎样识别的,这个问题可就有的探讨了。每一种编译器的识别方式不太一样,有的是在数组前开辟一个空间,(如32位机子,开辟4字节空间)来记录数组的大小,从而告知编译器;有的则是在数组连续空间结尾处设定分割字节(如在VC调试状态下的:0xcd、0xCC等字节)。总之肯定需要一定的方式告知计算机数组的大小。
第五题:这个要纠结到strlen函数的设置问题上了,strlen默认的终止符号式‘\0’,所以由于你的数组没有初始化,你每次编译的时候出现的结果很可能不同,(如果程序没有大的修改,每次编译结果很可能相同,你可以通过修改release和debug模式,;来迫使系统重新分配一下空间,来看一下,结果肯定是不一样的)。
希望对你有一些提示。
可以参考相关的书籍《操作系统》《C++反汇编与逆向技术分析》等