2

I have a c program I'm writing that I want to be portable and future compliant. The POSIX function strdup() is not in the current C standard, but it has been added to the C2x standard. Will this code work properly with C standard compliant compilers in the future.

Will it work on both POSIX and non POSIX systems?

my_strdup.h

#ifndef MY_STRDUP_H
#define MY_STRDUP_H

#include <string.h>

#ifndef strdup
#ifdef _MSC_VER
#if _MSC_VER > 1920
#define strdup _strdup
#endif
#else
#define strdup mystrdup      
#endif
#endif

char* mystrdup(const char* string_to_copy);
unsigned char* ucstrdup(const unsigned char* string_to_copy);

#endif  // MY_STRDUP_H

my_strdup.c

#include "my_strdup.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char* mystrdup(const char* string_to_copy)
{
    char* return_string = NULL;
    size_t length = strlen(string_to_copy);
    ++length;

    return_string = calloc(length, sizeof(*return_string));
    if (return_string)
    {
        memcpy(return_string, string_to_copy, length - 1);
    }

    return return_string;
}

unsigned char* ucstrdup(const unsigned char* string_to_copy)
{
    unsigned char* return_string = NULL;
    size_t length = strlen((const char*)string_to_copy);
    ++length;

    return_string = calloc(length, sizeof(*return_string));
    if (return_string)
    {
        memcpy(return_string, string_to_copy, length - 1);
    }

    return return_string;
}

Post Answer Update:

This code is part of a project I am working on, the code that uses this code can be found in 4 questions on Code Review. Those questions are all related to unit tests I am writing for this project.

Here are the questions on code review in the order asked:

  1. Hand Coded State Driven Lexical Analyzer in C With Unit Test Part A
  2. Hand Coded State Driven Lexical Analyzer in C With Unit Test Part B
  3. Part C
  4. Follow up to Part C

Feel free to write answers for the questions as long as they follow the Code Review Guidelines

pacmaninbw
  • 439
  • 1
  • 10
  • 22
  • 3
    Looks fine to me. But you don't need to duplicate all that code. Just have `ucstrdup()` call `strdup()` with appropriate casts. – Barmar Sep 03 '20 at 23:07
  • 3
    Will `strdup()` be a macro for certain? It seems unlikely. – Jonathan Leffler Sep 03 '20 at 23:26
  • 2
    What is your program doing? – Basile Starynkevitch Sep 03 '20 at 23:33
  • @JonathanLeffler in the `gcc` string.h file all of the functions are macros. – pacmaninbw Sep 04 '20 at 00:02
  • @pacmaninbw really ? `extern char *strdup (const char *__s) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__malloc__)) __attribute__ ((__nonnull__ (1)));` it does not look like macro for me – 0___________ Sep 04 '20 at 00:03
  • @BasileStarynkevitch This code is [part of a code review](https://codereview.stackexchange.com/questions/248817/common-unit-testing-code-follow-up?noredirect=1&lq=1). – pacmaninbw Sep 04 '20 at 00:05
  • do you review your own code? interesting ....... – 0___________ Sep 04 '20 at 00:08
  • 2
    That’s allowed; it isn’t required. So your test may fail on some systems with `strdup()` provided. You should probably plan to detect an appropriate version in `__STDC_VERSION__`. The official number for that won’t be known for a while, but you could make a reasonable guess, such as it will be larger than `202001L`. – Jonathan Leffler Sep 04 '20 at 00:08
  • @P__J__ look at the linked code reviews, there are 3 others. That's the only one of my own questions I ever reviewed. – pacmaninbw Sep 04 '20 at 00:09
  • @P__J__ https://github.com/gcc-mirror/gcc/blob/master/libssp/ssp/string.h – pacmaninbw Sep 04 '20 at 00:18
  • `#if __MISC_VISIBLE || __POSIX_VISIBLE >= 200809 || __XSI_VISIBLE >= 4 char *_EXFUN(strdup,(const char *)); #endif char *_EXFUN(_strdup_r,(struct _reent *, const char *)); #if __POSIX_VISIBLE >= 200809 char *_EXFUN(strndup,(const char *, size_t)); #endif char *_EXFUN(_strndup_r,(struct _reent *, const char *, size_t));` – 0___________ Sep 04 '20 at 00:22
  • @pacmaninbw as you see there is no one string.h – 0___________ Sep 04 '20 at 00:23
  • @pacmaninbw I would not use calloc to zero only 1 char. also ++length when you use it later only once makes not sense. computer will have to calculate ++ and then -1. – 0___________ Sep 04 '20 at 00:31
  • 2
    The *Functions* in `string.h` are provide in [gcc -master - string/](https://sourceware.org/git/?p=glibc.git;a=tree;f=string;h=9e9479f3c362e0d5886287173eaad4324e1fc5b5;hb=refs/heads/master) – David C. Rankin Sep 04 '20 at 02:01

1 Answers1

0

Read carefully the C11 standard n1570. For things like Arduino, you might not even have any malloc, and you could have some free-standing implemention of C11.

As a concrete example, the Linux kernel is coded in C, and your code could not be part of it.

Also see this answer providing some funny implementation of malloc (you could extend it to calloc...)

Will this code work properly with C standard compliant compilers in the future.

Of course not in general.

Look on many examples of toy operating systems on OSDEV.

You could have some operating system without  malloc or calloc but with a C compiler.

I have a c program I'm writing that I want to be portable and future compliant.

The motto I read somewhere is: there is no such thing as portable programs, just programs which have been ported (to some given systems)

Did you consider some approach inspired by GNU autoconf ? Your build automation could use preprocessing tricks and/or generate C code with e.g. GPP, SWIG or other tools.

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
  • 2
    He's obviously not targeting freestanding implementations, just non-POSIX. – Barmar Sep 03 '20 at 23:09
  • 4
    If you don’t have `free()`, it doesn’t make sense to worry about whether `strdup()` works. – Sneftel Sep 03 '20 at 23:21
  • 2
    Where does the C standard which you linked say that allocation functions are optional? – interjay Sep 03 '20 at 23:31
  • 1
    A freestanding implementation does not have to provide any `malloc` – Basile Starynkevitch Sep 03 '20 at 23:33
  • I've downloaded the C11 standard you pointed to and will read through it tomorrow. I doubt I would use the code in the header file on in the Linux Kernel and I would be very careful with any memory allocation in a kernel. – pacmaninbw Sep 04 '20 at 00:49
  • Thank you for the answer, I abandoned the approach I was taking and unconditionally provide a strdup() replacement called [SSF_strdup()](https://github.com/pacmaninbw/VMWithEditor/blob/master/VMWithEditor/safe_string_functions.c). – pacmaninbw Sep 09 '20 at 16:22