- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
代码:
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
typedef unsigned int uint32_t;
float average(int n_values, ... )
{
va_list var_arg;
int count;
float sum = 0;
va_start(var_arg, n_values);
for (count = 0; count < n_values; count += 1) {
sum += va_arg(var_arg, signed long long int);
}
va_end(var_arg);
return sum / n_values;
}
int main(int argc, char *argv[])
{
(void)argc;
(void)argv;
printf("hello world!\n");
uint32_t t1 = 1;
uint32_t t2 = 4;
uint32_t t3 = 4;
printf("result:%f\n", average(3, t1, t2, t3));
return 0;
}
当我在 ubuntu (x86_64) 中运行时,没问题。
lix@lix-VirtualBox:~/test/c$ ./a.out
hello world!
result:3.000000
lix@lix-VirtualBox:~/test/c$ uname -a
Linux lix-VirtualBox 4.4.0-116-generic #140-Ubuntu SMP Mon Feb 12 21:23:04 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
lix@lix-VirtualBox:~/test/c$
但是我在openwrt(ARM 32bit)中交叉编译运行时,就报错了。
[root@OneCloud_0723:/root/lx]#./helloworld
hello world!
result:13952062464.000000
[root@OneCloud_0723:/root/lx]#uname -a
Linux OneCloud_0723 3.10.33 #1 SMP PREEMPT Thu Nov 2 19:55:17 CST 2017 armv7l GNU/Linux
我知道不要使用错误类型的参数调用 va_arg。但是为什么我们可以在 x86_64 中得到正确的结果而不是在 arm 中?
谢谢。
最佳答案
在 x86-64 Linux 上,每个 32 位 arg 都在一个单独的 64 位寄存器中传递(因为这是 x86-64 System V 调用约定所要求的)。
调用者恰好将 32 位 arg 零扩展到 64 位寄存器中。 (这不是必需的;您程序中的未定义行为可能会让您被另一个在参数传递寄存器中留下大量垃圾的调用者咬住。)
被调用者 ( average()
) 正在寻找三个 64 位参数,并在调用者放置它们的相同寄存器中查找,所以它恰好可以工作。
在 32 位 ARM 上,long long
不适合单个寄存器,因此被调用者正在寻找 long long
args 肯定在与调用者放置的位置不同的地方寻找 uint32_t
参数。
被调用者看到的第一个 64 位 arg 可能是 ((long long)t1<<32) | t2
, 或相反。但是由于被调用者正在寻找 6x 32 位的 args,它会查看调用者根本不打算作为 args 的寄存器/内存。
(请注意,这可能会导致调用者在堆栈上的局部变量损坏,因为被调用者可以破坏堆栈参数。)
有关完整详细信息,请使用编译器 + 编译选项查看代码的 asm 输出,以查看源代码中的 C 未定义行为究竟导致了哪些行为。 objdump -d ./helloworld
应该可以解决问题,或者直接查看编译器输出:How to remove "noise" from GCC/clang assembly output? .
关于c - 为什么 va_arg() 在 x86_64 和 arm 上产生不同的效果?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49041919/
我有以下函数将传递的参数写入二进制文件。 void writeFile(FILE *fp, const int numOfChars, ...) { va_list ap; va_star
我正在制作一个类似于 printf 的函数,它需要接受一个字符串和参数,例如: form("整数 %d, 字符串 %s", 54, "STRING"); 并创建一个字符串“Integer 54,Str
为什么下面的代码给出EXC_BAD_ACCESS, could not access memory ? int combine_strings(char **outputStr,...) {
我的打印函数使用 va_arg 函数打印随机字符。我不明白为什么它不起作用。提前感谢您的帮助! #include #include #include int myprint(const char
在 main.c 中,我调用 function(2, "string", "yes") 哪里 void function(UINT16 id, const char *ptr_argDescr,
我想用这种方式编写一个带有可变参数的函数: static void configElement(U32 localFaultId, char* na
我正在研究可变函数和参数。 我注意到 va_arg 能够将对象转换为其他对象。例如,当下一个参数是 char 时,但您正在使用 va_arg 就像它应该是 int 一样,它会转换 char 到 int
我可以将类型转换为 va_arg 返回示例吗?据我所知,va_arg 无法读取返回 char/short int 类型 if (flags->size == 0) u->s = (char)v
我正在尝试编写一个带有格式字符串和一些可变数字参数的小函数。格式字符串采用表示不同数字类型的各种字符(c 表示 char,i 表示 int,d 表示 double 等),然后字符串中的每个字符采用该类
我是第一次尝试编写自己的 va_args 函数,但我遇到了一个问题,即大整数(仍在 int 范围内)被截断为 3 位数字,并且乱序! 这里是实现 void __sprintf(char * _stri
如果我调用 va_arg 的次数少于可变参数函数中传递的参数数量,是否会出现未定义的行为? 例如: #include void foo(unsigned n, ...) { va_list
全部, 我正在编写一个小型 C++ 应用程序,但一直被这个问题难倒。如果元素类型不是预期的,是否有一种方法可以在使用 va_arg 从 va_list 宏访问元素时创建(并稍后捕获)错误。例如:- c
使用以下代码,va_arg 将在第二次和第三次通过 vProcessType 时返回垃圾。 // va_list_test.cpp : Defines the entry point for the
我正在尝试创建一个函数,该函数在参数中采用可变数量的矩阵并将这些矩阵乘以第一个。我可以使用 va_arg 读取第一个,但下一次调用 va_arg 将导致访问冲突。 这是我声明方法的方式: templa
我做了一个简单的测试用例: static void va_test(char* str_arg, ...) { va_list ap; va_start(ap, str_arg); for
我想像这样用指针参数初始化一个链表: /* * Initialize a linked list using variadic arguments * Returns the number of
mystruct_t v = va_arg(a_list, mystruct_t); 就 C 规范而言,这可以吗(使用大于等于 int 大小的自定义数据类型)? 最佳答案 C 标准中没有关于将结构类型
我正在阅读一个 stdarg.h(下面的链接)头文件,它定义了 va_arg 宏,如下所示 /* * Increment ap to the next argument in the list wh
我知道如果我将像 void (*func)(void *) 这样的参数传递给可变参数函数,我可以像这样检索参数: void (*func)(void *) = va_arg( args, void (
这个问题不太可能对任何 future 的访客有帮助;它只与一个小的地理区域、一个特定的时间点或一个非常狭窄的情况相关,通常不适用于互联网的全局受众。如需帮助使这个问题更广泛适用,visit the h
我是一名优秀的程序员,十分优秀!