gpt4 book ai didi

c - 为什么我的 C 代码片段不起作用?简化版可以。为 unsigned long long 传递不带 VA_ARGS 的参数

转载 作者:太空宇宙 更新时间:2023-11-04 05:31:22 26 4
gpt4 key购买 nike

基本上我正在为专用系统编写 printf 函数,因此我想在不使用 VA_ARGS 宏的情况下传递可选数量的参数。我敲了一个简单的例子,这段代码有效:

#include <stdio.h>

void func(int i, ...);
int main(int argc, char *argv);

int main(int argc, char *argv) {

unsigned long long f = 6799000015ULL;
unsigned long long *g;

//g points to f
g = &f;

printf("natural: %llu in hex: %llX address: %x\n", *g, *g, g);

//put pointer onto stack
func(6, g, g);

return 0;
}

void func(int i, ...) {

unsigned long long *f;

//pop value off
f = *(&i + 1);

printf("address: %x natural: %llu in hex: %llX\n", f, *f, *f);

}

但是,我尝试将其传输到更大的示例 工作。

(在主函数中):

unsigned long long f = 6799000015ULL;
unsigned long long *g;

g = &f;

kprintf("ull test: 1=%U 2=%X 3=%x 4= 5=\n", g, g, g);

(我遇到麻烦的狡猾的 printf 函数。也许值得指出此代码确实适用于 ints、char 字符串或任何其他传递的 % 标志 而不是指针。 所做 的工作与未签名的工作之间的唯一区别long longs 是一个更大的,所以我传递值而不是确保我不会增加&format+ args 部分错误。这有意义吗?)

void kprintf(char *format, ...)
{
char buffer[KPRINTF_BUFFER_SIZE];

int bpos = 0; /* position to write to in buffer */
int fpos = 0; /* position of char to print in format string */
char ch; /* current character being processed*/

/*
* We have a variable number of paramters so we
* have to increment from the position of the format
* argument.
*/
int arg_offset = 1;

/*
* Think this through Phill. &format = address of format on stack.
* &(format + 1) = address of argument after format on stack.
* void *p = &(format + arg_offset);
* kprintf("xxx %i %s", 32, "hello");
* memory would look like = [ 3, 32, 5, "xxx", 32, "hello" ]
* get to 32 via p = &(format + 1); (int)p (because the int is copied, not a pointer)
* get to hello via p = &(format + 2); (char*)p;
*/

void *arg;
unsigned long long *llu;
arg = (void*) (&format + arg_offset);
llu = (unsigned long long*) *(&format + arg_offset);

while (1)
{
ch = format[fpos++];

if (ch == '\0')
break;

if (ch != '%')
buffer[bpos++] = ch;
else
{
ch = format[fpos++];
if (ch == 's')
bpos += strcpy(&buffer[bpos], KPRINTF_BUFFER_SIZE - bpos, (char*)arg);
else if (ch == '%')
buffer[bpos++] = '%';
else if (ch == 'i')
bpos += int_to_str(&buffer[bpos], KPRINTF_BUFFER_SIZE - bpos, *((int*)arg));
else if (ch == 'x')
bpos += int_to_hex_str(&buffer[bpos], KPRINTF_BUFFER_SIZE - bpos, *((int*)arg));
else if (ch == 'o')
bpos += int_to_oct_str(&buffer[bpos], KPRINTF_BUFFER_SIZE - bpos, *((int*)arg));
else if (ch == 'X') {
//arg is expected to be a pointer we need to further dereference.
bpos += unsigned_long_long_to_hex(&buffer[bpos], KPRINTF_BUFFER_SIZE - bpos, *llu);
} else if (ch == 'U') {
bpos += unsigned_long_long_to_str(&buffer[bpos], KPRINTF_BUFFER_SIZE - bpos, *llu);
} else
{
puts("invalid char ");
putch(ch);
puts(" passed to kprintf\n");
}

arg_offset++;
arg = (void *)(&format + arg_offset);
llu = (unsigned long long*) *(&format + arg_offset);
}
}

buffer[bpos] = '\0';
puts(buffer);
}

(以及它继续调用的 unsigned long long 函数):

int unsigned_long_long_to_hex(char *buffer, int max_size, unsigned long long number)
{
return ull_number_to_str(buffer, max_size, number, BASE_HEX);
}

int unsigned_long_long_to_str(char *buffer, int max_size, unsigned long long number) {
return ull_number_to_str(buffer, max_size, number, BASE_DECIMAL);
}

int ull_number_to_str(char *buffer, int max_size, unsigned long long number, int base) {

int bufpos = 0;

unsigned int lo_byte = (unsigned int) number;
unsigned int hi_byte = (unsigned int) (number >> 32);

bufpos = number_to_str(buffer, max_size, lo_byte, base);
bufpos += number_to_str(buffer + bufpos, max_size, hi_byte, base);

return bufpos;

}

#define NUMERIC_BUFF_SIZE (11 * (ADDRESS_SIZE / 32))

int number_to_str(char *buffer, int max_size, int number, int base)
{
char *char_map = "0123456789ABCDEF";

int remain = 0;
char buff_stack[NUMERIC_BUFF_SIZE];
int stk_pnt = 0;
int bpos = 0;

/* with this method of parsing, the digits come out backwards */
do
{
if (stk_pnt > NUMERIC_BUFF_SIZE)
{
puts("Number has too many digits to be printed. Increasse NUMBERIC_BUFF_SIZE\n");
return 0;
}

remain = number % base;
number = number / base;
buff_stack[stk_pnt++] = char_map[remain];
} while (number > 0);

/* before writing...ensure we have enough room */
if (stk_pnt > max_size)
{
//error. do something?
puts("number_to_str passed number with too many digits to go into buffer\n");
//printf("error. stk_pnt > max_size (%d > %d)\n", stk_pnt, max_size);
return 0;
}

/* reorder */
while (stk_pnt > 0)
buffer[bpos++] = buff_stack[--stk_pnt];

return bpos;
}

抱歉各位,我看不出我做错了什么。我很欣赏这是一个“代码墙”类型的场景,但希望有人能看到我做错了什么。我很欣赏你可能不喜欢不使用 VA_ARGS 但我不明白为什么这种技术不应该只是工作?而且,我也正在与 -nostdlib 链接。如果有人可以提供帮助,我将不胜感激。此外,这并不意味着是生产质量代码,所以如果我缺乏一些 C 基础知识,请随意对其进行建设性的:-)

最佳答案

以这种方式编码是个坏主意。使用 stdarg.h

在极少数情况下(我根据名称 kprintf 推测)您正在从事爱好内核或嵌入式项目并希望避免使用标准库,我建议至少编写您的自己的(体系结构和编译器特定的)一组符合众所周知的接口(interface)和代码的 stdarg 宏。这样你的代码就不会通过取消引用最后一个参数的地址而看起来像这样的 WTF。

您可以制作一个存储最后已知地址的 va_list 类型,并且您的 va_arg 宏可以适本地对齐该类型的 sizeof它通过并相应地推进指针。对于我为 x86 制定的大多数约定,每种类型都被提升为 32 位...

关于c - 为什么我的 C 代码片段不起作用?简化版可以。为 unsigned long long 传递不带 VA_ARGS 的参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4550100/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com