小编Ken*_*eth的帖子

#define多个文件中的范围

我有一个像这样的主文件:

main_a.c:

#define MAIN_A

#include <stdio.h>
#include "shared.h"

extern int i;
int main() {
  printf("i is: %d\n", i);
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

我想在shared.h中使用这样的定义:

shared.h

#if defined(MAIN_A)
# define A
#endif
Run Code Online (Sandbox Code Playgroud)

所以我可以根据主文件是否存在来声明变量,如下所示:

shared.c

#include "shared.h"

#if defined(A)
int i = 1;
#else
int i = 0;
#endif
Run Code Online (Sandbox Code Playgroud)

我使用makefile构建它,如下所示:

Makefile文件:

all : a
    ./a

a : main_a.o shared.o
    gcc -o $@ $^

%.o : %.c
    gcc -c $<
Run Code Online (Sandbox Code Playgroud)

然而这打印

i is: 0
Run Code Online (Sandbox Code Playgroud)

现在我的问题是:为什么编译共享模块时定义似乎丢失了?我知道主模块是先编译的,所以定义应该在编译shared.c时解决.

我怀疑的是,预处理器可能会在每个模块构建开始时运行,而不仅仅是在项目开始时运行.如果这是正确的,有一种方法可以一次编译多个模块,以便在我上面尝试时使用预处理器吗?

c scope c-preprocessor

13
推荐指数
1
解决办法
1万
查看次数

C中的循环函数指针问题

我试图找出如何声明一个函数,该函数返回一个返回函数的函数的指针.这是一个循环问题,我不知道这是否可以在c中完成.这是我正在尝试做的一个说明性示例(它不起作用):

typedef (*)(void) (*fp)(void);

fp funkA(void) {
    return funkB;
}

fp funkB(void) {
    return funkA;
}
Run Code Online (Sandbox Code Playgroud)

c pointers function

7
推荐指数
1
解决办法
1320
查看次数

char和通常的算术转换规则

我知道这个问题已被提出并且似乎已经回答了无数次,但我似乎无法将答案与我自己的经验相匹配.

C标准规定,对于加法"两个操作数应具有算术类型"(6.5.6.1).Arithemitc类型包括整数和浮点类型(6.2.5.18),最后整数类型是char,short,int,long和long long,它们以有符号和无符号类型(6.2.5.4和6.2.5.6)存在.根据通常算术转换的规则"如果两个操作数具有相同的类型,则不需要进一步转换." 到现在为止还挺好.

我的理解,正如"C书"中所示,"[n] o算术由C以比int短的精度完成",这是应用积分推广的地方.我在标准中找不到对此的参考,我似乎已经多次看过这个.

由于unsigned char是一种算术类型,并且通常算术转换的规则表明相同类型的操作数不需要转换,为什么需要进行积分提升?

我使用两个不同的编译器测试了这个.我写了一个简单的程序,它添加了char:

unsigned char a = 1;
unsigned char b = 2;
unsigned char c = a + b;
Run Code Online (Sandbox Code Playgroud)

目标平台是使用8位架构的Atmel Mega8 uC.因此,如果操作数应该进行整体提升,则整数加法将需要使用两个寄存器.

使用imagecraft avr编译器进行编译,没有优化,并且启用了严格的ANSI C可移植性选项,产生了这个汇编代码:

mov R16, R20
add R16, R18
Run Code Online (Sandbox Code Playgroud)

使用avr-gcc(我不知道类似于gcc的-strict的ANSI开关):

$ avr-gcc -O0 -mmcu=atmega8 -S -c main.c
Run Code Online (Sandbox Code Playgroud)

结果汇编:

ldd r25,Y+1
ldd r24,Y+2
add r24,r25
std Y+3,r24
Run Code Online (Sandbox Code Playgroud)

两种情况下的结果代码都在单个字节上运行.我得到类似的结果| 和&和逻辑|| 和&&.这是否意味着该标准允许对charecter类型进行算术运算而不进行整数提升,或者仅仅意味着这些编译器不是标准的兼容性?


额外:

事实证明,这一切都取决于存储结果的类型.上面显示的示例仅在结果存储在char中时才为真,并且它不依赖于添加的结果.将a设置为0xFF并将b设置为1会生成完全相同的汇编代码.

如果c的类型更改为unsigned int,则生成的程序集如下所示:

mov R2,R20
clr R3
mov R16,R18 
clr R17
add R16,R2 
adc R17,R3 
Run Code Online (Sandbox Code Playgroud)

即使在结果可以保持在单个字节中的情况下,即a = 1且b = 2.

c types type-conversion

6
推荐指数
1
解决办法
3174
查看次数

在链接静态库时,如何将目标代码复制到可执行文件中?

我正在阅读O'Reilly的书21世纪C,其中作者声称在链接静态库时"编译器[有效地]将库的相关内容复制到最终的可执行文件中".

我试图通过创建自己的包含此模块的静态库来测试它:

static char szStr[64];

char* single_func() {
    strcpy(szStr, "Hello string!\r\n");
    return szStr;
}

void func0() {
    strcpy(szStr, "Hello");
}

char* func1() {
    strcat(szStr, " string!\r\n");
    return szStr;
}
Run Code Online (Sandbox Code Playgroud)

用于测试创建的c文件,其中一个调用single_func(),另一个调用func0()和func1().

在这两种情况下,生成的可执行文件都是751290B.如果我直接从模块调用strcpy和strcat,那么两个可执行文件最终都是7215B.

这不与上述声明冲突,还是我错过了一些关于链接的细节?

一个相关的问题是静态库是1600B,那么这个增加的大小来自哪里?


额外:

两个主文件只包括调用函数和打印结果,如下所示:

main0:

#include <stdio.h>
#include "sharedlib.h"
int main() {
    char* szStr = single_func();
    printf("%s", szStr);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

MAIN1:

#include <stdio.h>
#include "sharedlib.h"
int main() {
    char* szStr;
    func0();
    szStr = func1();
    printf("%s", szStr);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

文件编译如下:

gcc -static main0.c -L. -lsharedlib -o …
Run Code Online (Sandbox Code Playgroud)

c linker static-libraries

5
推荐指数
1
解决办法
1114
查看次数

混淆File.dirname的行为

我使用Ruby 1.9.3编写了几个用于系统管理的小Ruby脚本.在一个脚本中我使用:

File.dirname(__FILE__)
Run Code Online (Sandbox Code Playgroud)

获取脚本文件的目录.这将返回一个相对路径,但是当我从第二个脚本调用脚本时,File.dirname返回一个绝对路径.

Ruby Doc在其示例中列出了绝对返回路径,而我在Ruby论坛上发现了一个讨论,其中用户说dirname应该只返回相对路径.

我使用Ruby Forums建议的解决方案来使用File.expand_path总是得到这样的绝对路径:

File.expand_path(File.dirname(__FILE__))
Run Code Online (Sandbox Code Playgroud)

但有没有办法使行为dirname一致?


更新:

为了扩展Janathan Cairs的答案,我制作了两个脚本:

s1.rb:

puts "External script __FILE__: #{File.dirname(__FILE__)}"
Run Code Online (Sandbox Code Playgroud)

s0.rb:

puts "Local script __FILE__: #{File.dirname(__FILE__)}"
require './s1.rb'
Run Code Online (Sandbox Code Playgroud)

运行./s0.rb会给出以下输出:

Local script __FILE__: .
External script __FILE__: /home/kenneth/Pictures/wp/rip_vault
Run Code Online (Sandbox Code Playgroud)

ruby

4
推荐指数
1
解决办法
5629
查看次数

C switch 语句中的最终子句(可能使用 goto)

我可以在 C 开关中使用类似 javas finally 子句的东西。我的大多数案例都有一组共享的功能,我想将其放在一个案例中。我正在考虑使用 goto 语句来实现这一点,充分了解 goto 代码混淆能力,将共享案例放在 switch 语句的底部似乎仍然是比将共享功能分区到单独函数中更“干净”的方法。

\n\n

不管怎样,我一直在尝试做这样的事情:

\n\n
switch( x ) {\ncase 0:\n    printf("Case 0\\n");\n    goto case 2;\n    break;\ncase 1:\n    printf("Case 1\\n");\n    goto case 2;\n    break;\ncase 2:\n    printf("Case 2\\n");\n    break;\ndefault:\n    // do nothing\n    break;\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

但是,使用 gcc 会失败并出现错误

\n\n
error: expected identifier or \xe2\x80\x98*\xe2\x80\x99 before \xe2\x80\x98case\xe2\x80\x99\n
Run Code Online (Sandbox Code Playgroud)\n\n

关于如何使其发挥作用有什么建议吗?或者可能有更好的方法?

\n

c goto switch-statement

1
推荐指数
1
解决办法
7205
查看次数

eclipse无法解决所有包含问题

我正在使用eclipse中的avr项目并包含编译器提供的文件.Eclipse识别代码中的包含(即#include没有问号),但它不解析包含文件中的定义,即PINA不被识别为内存地址.

我试图将include目录添加为Paths和Symbols中的库路径.我试图将它添加为构建设置的库路径.两个人都没有工作.

我正在使用Eclipse Indigo和ImageCraft编译器.此外,在项目中,我已将imagecraft的include目录作为链接(以启用搜索).

有任何想法吗?

eclipse avr

1
推荐指数
1
解决办法
5439
查看次数

关于int的未定义增量的警告

我对avr-gcc有一个奇怪的问题.如果我这样做:

int i = 0;
i = ++i;
Run Code Online (Sandbox Code Playgroud)

它导致编译器警告:

warning: operation on ‘i’ may be undefined
Run Code Online (Sandbox Code Playgroud)

这有什么不对?

如果它被重写为

i = i + 1;
Run Code Online (Sandbox Code Playgroud)

它不会导致警告.

avr-gcc是版本4.3.4,我在Ubuntu 10.04上运行它.

c avr-gcc

1
推荐指数
1
解决办法
317
查看次数